Merge "Clarify ownership for NativeHandle::mHandle"
diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT
new file mode 100644
index 0000000..e74d217
--- /dev/null
+++ b/adb/SYNC.TXT
@@ -0,0 +1,84 @@
+This file tries to document file related requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here. See the SERVICES.TXT to learn more
+about the other requests that are possible.
+
+SYNC SERVICES:
+
+
+Requesting the sync service ("sync:") using the protocol as described in
+SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that
+differ from the regular adb protocol. The connection stays in sync mode until
+explicitly terminated (see below).
+
+After the initial "sync:" command is sent the server must respond with either
+"OKAY" or "FAIL" as per usual. 
+
+In sync mode both the server and the client will frequently use eight-byte
+packets to communicate in this document called sync request and sync
+responses. The first four bytes is an id and specifies sync request is
+represented by four utf-8 characters. The last four bytes is a Little-Endian
+integer, with various uses. This number will be called "length" below. In fact
+all binary integers are Little-Endian in the sync mode. Sync mode is
+implicitly exited after each sync request, and normal adb communication
+follows as described in SERVICES.TXT.
+
+The following sync requests are accepted:
+LIST - List the files in a folder
+SEND - Send a file to device
+RECV - Retreive a file from device
+
+Not yet documented:
+STAT - Stat a file
+ULNK - Unlink (remove) a file. (Not currently supported)
+
+For all of the sync request above the must be followed by length number of
+bytes containing an utf-8 string with a remote filename.
+
+LIST:
+Lists files in the directory specified by the remote filename. The server will
+respond with zero or more directory entries or "dents".
+
+The directory entries will be returned in the following form
+1. A four-byte sync response id beeing "DENT"
+2. A four-byte integer representing file mode.
+3. A four-byte integer representing file size.
+4. A four-byte integer representing last modified time.
+5. A four-byte integer representing file name length.
+6. length number of bytes containing an utf-8 string representing the file
+   name.
+
+When an sync response "DONE" is received the listing is done.
+
+SEND:
+The remote file name is split into two parts separated by the last
+comma (","). The first part is the actual path, while the second is a decimal
+encoded file mode containing the permissions of the file on device.
+
+Note that some file types will be deleted before the copying starts, and if
+the transfer fails. Some file types will not be deleted, which allows
+  adb push disk_image /some_block_device
+to work.
+
+After this the actual file is sent in chunks. Each chucks has the following
+format.
+A sync request with id "DATA" and length equal to the chunk size. After
+follows chunk size number of bytes. This is repeated until the file is
+transfered. Each chunk must not be larger than 64k.
+
+When the file is tranfered a sync request "DONE" is sent, where length is set
+to the last modified time for the file. The server responds to this last
+request (but not to chuck requests) with an "OKAY" sync response (length can
+be ignored).
+
+
+RECV:
+Retrieves a file from device to a local file. The remote path is the path to
+the file that will be returned. Just as for the SEND sync request the file
+received is split up into chunks. The sync response id is "DATA" and length is
+the chuck size. After follows chunk size number of bytes. This is repeated
+until the file is transfered. Each chuck will not be larger than 64k.
+
+When the file is transfered a sync resopnse "DONE" is retrieved where the
+length can be ignored.
+
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index cd5885e..6fc55df 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -90,6 +90,8 @@
 #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
@@ -210,6 +212,7 @@
     VENDOR_ID_HUAWEI,
     VENDOR_ID_INQ_MOBILE,
     VENDOR_ID_INTEL,
+    VENDOR_ID_INTERMEC,
     VENDOR_ID_IRIVER,
     VENDOR_ID_KOBO,
     VENDOR_ID_K_TOUCH,
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 77fcbe0..f6d8f0c 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,35 +1,93 @@
 LOCAL_PATH:= $(call my-dir)
 
-debuggerd_2nd_arch_var_prefix :=
-include $(LOCAL_PATH)/debuggerd.mk
-
-ifdef TARGET_2ND_ARCH
-debuggerd_2nd_arch_var_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX)
-include $(LOCAL_PATH)/debuggerd.mk
-endif
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
 include $(CLEAR_VARS)
 
-LOCAL_CFLAGS += -DWITH_VFP
+LOCAL_SRC_FILES:= \
+	backtrace.cpp \
+	debuggerd.cpp \
+	getevent.cpp \
+	tombstone.cpp \
+	utility.cpp \
+
+LOCAL_SRC_FILES_arm    := arm/machine.cpp
+LOCAL_SRC_FILES_arm64  := arm64/machine.cpp
+LOCAL_SRC_FILES_mips   := mips/machine.cpp
+LOCAL_SRC_FILES_x86    := x86/machine.cpp
+LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
+
+LOCAL_CONLYFLAGS := -std=gnu99
+LOCAL_CPPFLAGS := -std=gnu++11
+LOCAL_CFLAGS := \
+	-Wall \
+	-Wno-array-bounds \
+	-Werror \
+	-Wno-unused-parameter \
+
+ifeq ($(ARCH_ARM_HAVE_VFP),true)
+LOCAL_CFLAGS_arm += -DWITH_VFP
+endif # ARCH_ARM_HAVE_VFP
 ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS += -DWITH_VFP_D32
+LOCAL_CFLAGS_arm += -DWITH_VFP_D32
 endif # ARCH_ARM_HAVE_VFP_D32
 
-LOCAL_SRC_FILES := vfp-crasher.c arm/vfp.S
+LOCAL_SHARED_LIBRARIES := \
+	libbacktrace \
+	libc \
+	libcutils \
+	liblog \
+	libselinux \
+
+include external/stlport/libstlport.mk
+
+LOCAL_MODULE := debuggerd
+LOCAL_MODULE_STEM_32 := debuggerd
+LOCAL_MODULE_STEM_64 := debuggerd64
+LOCAL_MULTILIB := both
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.c
+LOCAL_SRC_FILES_arm    := arm/crashglue.S
+LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
+LOCAL_SRC_FILES_mips   := mips/crashglue.S
+LOCAL_SRC_FILES_x86    := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+
+LOCAL_MODULE := crasher
+LOCAL_MODULE_STEM_32 := crasher
+LOCAL_MODULE_STEM_64 := crasher64
+LOCAL_MULTILIB := both
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+ifeq ($(ARCH_ARM_HAVE_VFP),true)
+LOCAL_MODULE_TARGET_ARCH += arm
+LOCAL_SRC_FILES_arm := arm/vfp.S
+LOCAL_CFLAGS_arm += -DWITH_VFP
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_CFLAGS_arm += -DWITH_VFP_D32
+endif # ARCH_ARM_HAVE_VFP_D32
+endif # ARCH_ARM_HAVE_VFP == true
+
+LOCAL_SRC_FILES_arm64 := arm64/vfp.S
+LOCAL_MODULE_TARGET_ARCH += arm64
+
+LOCAL_SRC_FILES := vfp-crasher.c
 LOCAL_MODULE := vfp-crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-LOCAL_MODULE_TARGET_ARCH := arm
-include $(BUILD_EXECUTABLE)
-endif # ARCH_ARM_HAVE_VFP == true
 
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := vfp-crasher.c arm64/vfp.S
-LOCAL_MODULE := vfp-crasher64
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-LOCAL_MODULE_TARGET_ARCH := arm64
+LOCAL_MODULE_STEM_32 := vfp-crasher
+LOCAL_MODULE_STEM_64 := vfp-crasher64
+LOCAL_MULTILIB := both
+
 include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/debuggerd.mk b/debuggerd/debuggerd.mk
deleted file mode 100644
index a3982c1..0000000
--- a/debuggerd/debuggerd.mk
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	backtrace.cpp \
-	debuggerd.cpp \
-	getevent.cpp \
-	tombstone.cpp \
-	utility.cpp \
-
-LOCAL_SRC_FILES_arm    := arm/machine.cpp
-LOCAL_SRC_FILES_arm64  := arm64/machine.cpp
-LOCAL_SRC_FILES_mips   := mips/machine.cpp
-LOCAL_SRC_FILES_x86    := x86/machine.cpp
-LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
-
-LOCAL_CONLYFLAGS := -std=gnu99
-LOCAL_CPPFLAGS := -std=gnu++11
-LOCAL_CFLAGS := \
-	-Wall \
-	-Wno-array-bounds \
-	-Werror \
-	-Wno-unused-parameter \
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP
-endif # ARCH_ARM_HAVE_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
-
-LOCAL_SHARED_LIBRARIES := \
-	libbacktrace \
-	libc \
-	libcutils \
-	liblog \
-	libselinux \
-
-include external/stlport/libstlport.mk
-
-ifeq ($(TARGET_IS_64_BIT)|$(debuggerd_2nd_arch_var_prefix),true|)
-LOCAL_MODULE := debuggerd64
-LOCAL_NO_2ND_ARCH := true
-else
-LOCAL_MODULE := debuggerd
-LOCAL_32_BIT_ONLY := true
-endif
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.c
-LOCAL_SRC_FILES_arm    := arm/crashglue.S
-LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
-LOCAL_SRC_FILES_mips   := mips/crashglue.S
-LOCAL_SRC_FILES_x86    := x86/crashglue.S
-LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-
-LOCAL_2ND_ARCH_VAR_PREFIX := $(debuggerd_2nd_arch_var_prefix)
-
-ifeq ($(TARGET_IS_64_BIT)|$(debuggerd_2nd_arch_var_prefix),true|)
-LOCAL_MODULE := crasher64
-LOCAL_NO_2ND_ARCH := true
-else
-LOCAL_MODULE := crasher
-LOCAL_32_BIT_ONLY := true
-endif
-include $(BUILD_EXECUTABLE)
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
index 0f32dbf..6aa7400 100644
--- a/fastbootd/Android.mk
+++ b/fastbootd/Android.mk
@@ -45,19 +45,17 @@
 LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
 LOCAL_LDFLAGS := -ldl
 
-LOCAL_SHARED_LIBRARIES := \
-    libhardware \
-    libcrypto \
-    libhardware_legacy \
-    libmdnssd
-
 LOCAL_STATIC_LIBRARIES := \
-    libsparse_static \
     libc \
+    libcrypto_static \
     libcutils \
+    libmdnssd \
+    libsparse_static \
     libz
 
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_HAL_STATIC_LIBRARIES := libvendortrigger
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
 
 include $(BUILD_EXECUTABLE)
 
@@ -84,21 +82,11 @@
 
 include $(BUILD_EXECUTABLE)
 
+# vendor trigger HAL
 include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/include \
-
-LOCAL_STATIC_LIBRARIES := \
-    $(EXTRA_STATIC_LIBS) \
-    libcutils
-
-LOCAL_SRC_FILES := \
-    other/vendor_trigger.c
-
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_MODULE := libvendortrigger.default
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-
-
-include $(BUILD_SHARED_LIBRARY)
+LOCAL_SRC_FILES := vendor_trigger_default.c
+LOCAL_STATIC_LIBRARIES := libcutils
+include $(BUILD_STATIC_LIBRARY)
diff --git a/fastbootd/other/vendor_trigger.c b/fastbootd/other/vendor_trigger.c
deleted file mode 100644
index 101959b..0000000
--- a/fastbootd/other/vendor_trigger.c
+++ /dev/null
@@ -1,96 +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 "vendor_trigger.h"
-#include "debug.h"
-
-unsigned int debug_level = DEBUG;
-
-static const int version = 1;
-
-int check_version(const int fastboot_version, int *libversion) {
-    *libversion = version;
-    return !(fastboot_version == version);
-}
-
-int gpt_layout(struct GPT_content *table) {
-    D(DEBUG, "message from libvendor");
-    return 0;
-}
-
-int oem_cmd(const char *arg, const char **response) {
-    D(DEBUG, "message from libvendor, oem catched request %s", arg);
-    return 0;
-}
-
-static int close_triggers(struct vendor_trigger_t *dev)
-{
-    if (dev)
-        free(dev);
-
-    return 0;
-}
-
-static int open_triggers(const struct hw_module_t *module, char const *name,
-                         struct hw_device_t **device) {
-    struct vendor_trigger_t *dev = malloc(sizeof(struct vendor_trigger_t));
-    klog_init();
-    klog_set_level(6);
-
-    memset(dev, 0, sizeof(*dev));
-    dev->common.module = (struct hw_module_t *) module;
-    dev->common.close  = (int (*)(struct hw_device_t *)) close_triggers;
-
-    dev->gpt_layout = gpt_layout;
-    dev->oem_cmd = oem_cmd;
-
-    *device = (struct hw_device_t *) dev;
-
-    return 0;
-}
-
-
-static struct hw_module_methods_t trigger_module_methods = {
-    .open = open_triggers,
-};
-
-struct hw_module_t HAL_MODULE_INFO_SYM = {
-    .tag = HARDWARE_MODULE_TAG,
-    .version_major = 1,
-    .version_minor = 0,
-    .id = TRIGGER_MODULE_ID,
-    .name = "vendor trigger library for fastbootd",
-    .author = "Google, Inc.",
-    .methods = &trigger_module_methods,
-};
-
diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c
index e63e64d..df0f895 100644
--- a/fastbootd/trigger.c
+++ b/fastbootd/trigger.c
@@ -39,52 +39,19 @@
 
 static const int version = 1;
 
-static struct vendor_trigger_t *triggers = NULL;
-
 int load_trigger() {
-    int err;
-    hw_module_t* module;
-    hw_device_t* device;
     int libversion;
 
-    err = hw_get_module(TRIGGER_MODULE_ID, (hw_module_t const**)&module);
-
-    if (err == 0) {
-        err = module->methods->open(module, NULL, &device);
-
-        if (err == 0) {
-            triggers = (struct vendor_trigger_t *) device;
-        } else {
-            D(WARN, "Libvendor load error");
-            return 1;
-        }
-    }
-    else {
-        D(WARN, "Libvendor not load: %s", strerror(-err));
-        return 0;
+    if (trigger_init() != 0) {
+        D(ERR, "libvendortrigger failed to initialize");
+        return 1;
     }
 
-    if (triggers->check_version != NULL &&
-        triggers->check_version(version, &libversion)) {
-
-        triggers = NULL;
+    if (trigger_check_version(version, &libversion)) {
         D(ERR, "Library report incompability");
         return 1;
     }
+
     D(INFO, "libvendortrigger loaded");
-
     return 0;
 }
-
-int trigger_oem_cmd(const char *arg, const char **response) {
-    if (triggers != NULL && triggers->oem_cmd != NULL)
-        return triggers->oem_cmd(arg, response);
-    return 0;
-}
-
-int trigger_gpt_layout(struct GPT_content *table) {
-    if (triggers != NULL && triggers->gpt_layout != NULL)
-        return triggers->gpt_layout(table);
-    return 0;
-}
-
diff --git a/fastbootd/trigger.h b/fastbootd/trigger.h
index 404acb4..d2d9573 100644
--- a/fastbootd/trigger.h
+++ b/fastbootd/trigger.h
@@ -37,9 +37,4 @@
 
 int load_trigger();
 
-/* same as in struct triggers */
-
-int trigger_gpt_layout(struct GPT_content *table);
-int trigger_oem_cmd(const char *arg, const char **response);
-
 #endif
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/vendor_trigger.h
similarity index 68%
rename from fastbootd/include/vendor_trigger.h
rename to fastbootd/vendor_trigger.h
index 51204fa..0c83be6 100644
--- a/fastbootd/include/vendor_trigger.h
+++ b/fastbootd/vendor_trigger.h
@@ -32,38 +32,37 @@
 #ifndef __VENDOR_TRIGGER_H_
 #define __VENDOR_TRIGGER_H_
 
-#define TRIGGER_MODULE_ID "fastbootd"
-#include <hardware/hardware.h>
-
 __BEGIN_DECLS
 
 struct GPT_entry_raw;
 struct GPT_content;
 
 /*
- * Structer with function pointers may become longer in the future
+ * Implemented in libvendortrigger to handle platform-specific behavior.
  */
 
-struct vendor_trigger_t {
-    struct hw_device_t common;
+/*
+ * 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 at the beggining and shoud never be changed
-     *
-     * 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 (*check_version)(const int version, int *libversion);
+/*
+ * 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 (* gpt_layout)(struct GPT_content *);
-    int (* oem_cmd)(const char *arg, const char **response);
-};
+/*
+ * 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
 
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/vendor_trigger_default.c
similarity index 62%
copy from fastbootd/include/vendor_trigger.h
copy to fastbootd/vendor_trigger_default.c
index 51204fa..3627024 100644
--- a/fastbootd/include/vendor_trigger.h
+++ b/fastbootd/vendor_trigger_default.c
@@ -29,42 +29,30 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __VENDOR_TRIGGER_H_
-#define __VENDOR_TRIGGER_H_
+#include <stdlib.h>
+#include <cutils/klog.h>
+#include <vendor_trigger.h>
 
-#define TRIGGER_MODULE_ID "fastbootd"
-#include <hardware/hardware.h>
+static const int version = 1;
 
-__BEGIN_DECLS
+int trigger_init(void) {
+    klog_init();
+    klog_set_level(7);
+    return 0;
+}
 
-struct GPT_entry_raw;
-struct GPT_content;
+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);
+}
 
-/*
- * Structer with function pointers may become longer in the future
- */
+int trigger_gpt_layout(struct GPT_content *table) {
+    KLOG_DEBUG("fastbootd", "%s: %p", __func__, table);
+    return 0;
+}
 
-struct vendor_trigger_t {
-    struct hw_device_t common;
-
-    /*
-     * This function runs at the beggining and shoud never be changed
-     *
-     * 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 (*check_version)(const int version, int *libversion);
-
-
-    /*
-     * Return value -1 forbid the action from the vendor site and sets errno
-     */
-    int (* gpt_layout)(struct GPT_content *);
-    int (* oem_cmd)(const char *arg, const char **response);
-};
-
-__END_DECLS
-
-#endif
+int trigger_oem_cmd(const char *arg, const char **response) {
+    KLOG_DEBUG("fastbootd", "%s: %s", __func__, arg);
+    return 0;
+}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index c4f27a0..9ac68cd 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -54,6 +54,32 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
+/**
+ * TODO - Remove to enable always on encryption for all devices
+ * This limits the machines on which this feature is enabled
+ * Remove call from fs_mgr_mount_all as well
+ */
+static const char* serial_numbers[] = {
+  "039b83b8437e9637",
+  0
+};
+
+static int serial_matches()
+{
+    char tmp[PROP_VALUE_MAX];
+    *tmp = 0;
+    __system_property_get("ro.serialno", tmp);
+
+    const char** i;
+    for (i = serial_numbers; *i; ++i) {
+        if (!strcmp(*i, tmp)) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 /*
  * gettime() - returns the time in seconds of the system's monotonic clock or
  * zero on error.
@@ -254,6 +280,22 @@
                        fstab->recs[i].fs_options);
 
         if (!mret) {
+            /* If this is encryptable, need to trigger encryption */
+            if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
+                if (serial_matches() && umount(fstab->recs[i].mount_point) == 0) {
+                    if (!encryptable) {
+                        encryptable = 2;
+                    } else {
+                        ERROR("Only one encryptable/encrypted partition supported");
+                        encryptable = 1;
+                    }
+                } else {
+                    INFO("Could not umount %s - allow continue unencrypted",
+                         fstab->recs[i].mount_point);
+                    continue;
+                }
+            }
+
             /* Success!  Go get the next one */
             continue;
         }
@@ -287,12 +329,8 @@
 
     if (error_count) {
         return -1;
-    }
-
-    if (encryptable) {
-        return 1;
     } else {
-        return 0;
+        return encryptable;
     }
 }
 
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 3e6a4b1..9368225 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -302,6 +302,16 @@
         }
         break;
 
+    case BATTERY_PROP_CAPACITY:
+        if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
+            val->valueInt =
+                getIntField(mHealthdConfig->batteryCapacityPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
     default:
         break;
     }
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 247c996..66f3637 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -34,6 +34,12 @@
 int str_parms_add_float(struct str_parms *str_parms, const char *key,
                         float value);
 
+// Returns non-zero if the str_parms contains the specified key.
+int str_parms_has_key(struct str_parms *str_parms, const char *key);
+
+// Gets value associated with the specified key (if present), placing it in the buffer
+// pointed to by the out_val parameter.  Returns the length of the returned string value.
+// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched.
 int str_parms_get_str(struct str_parms *str_parms, const char *key,
                       char *out_val, int len);
 int str_parms_get_int(struct str_parms *str_parms, const char *key,
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 1c8f107..dbd5e25 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -17,13 +17,14 @@
 #ifndef _LIBS_CUTILS_TRACE_H
 #define _LIBS_CUTILS_TRACE_H
 
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
 #include <unistd.h>
-#include <cutils/compiler.h>
 
+#include <cutils/compiler.h>
 #ifdef ANDROID_SMP
 #include <cutils/atomic-inline.h>
 #else
@@ -217,8 +218,8 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%d", getpid(),
-                name, cookie);
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
+                getpid(), name, cookie);
         write(atrace_marker_fd, buf, len);
     }
 }
@@ -235,8 +236,8 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%d", getpid(),
-                name, cookie);
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
+                getpid(), name, cookie);
         write(atrace_marker_fd, buf, len);
     }
 }
@@ -253,7 +254,7 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d",
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
                 getpid(), name, value);
         write(atrace_marker_fd, buf, len);
     }
@@ -270,7 +271,7 @@
         char buf[ATRACE_MESSAGE_LENGTH];
         size_t len;
 
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%lld",
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
                 getpid(), name, value);
         write(atrace_marker_fd, buf, len);
     }
diff --git a/init/Android.mk b/init/Android.mk
index 740d10f..15a23be 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -17,6 +17,8 @@
 	ueventd_parser.c \
 	watchdogd.c
 
+LOCAL_CFLAGS    += -Wno-unused-parameter
+
 ifeq ($(strip $(INIT_BOOTCHART)),true)
 LOCAL_SRC_FILES += bootchart.c
 LOCAL_CFLAGS    += -DBOOTCHART=1
diff --git a/init/builtins.c b/init/builtins.c
index a168062..a857c98 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -501,8 +501,12 @@
         return -1;
     }
 
-    /* ret is 1 if the device appears encrypted, 0 if not, and -1 on error */
-    if (ret == 1) {
+    /* ret is 2 if device needs encrypted, 1 if the device appears encrypted,
+     * 0 if not, and -1 on error */
+    if (ret == 2) {
+        property_set("ro.crypto.state", "unencrypted");
+        property_set("vold.decrypt", "trigger_encryption");
+    } else if (ret == 1) {
         property_set("ro.crypto.state", "encrypted");
         property_set("vold.decrypt", "trigger_default_encryption");
     } else if (ret == 0) {
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 7cfbcb3..1edef11 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -240,6 +240,10 @@
     return ret;
 }
 
+int str_parms_has_key(struct str_parms *str_parms, const char *key) {
+    return hashmapGet(str_parms->map, (void *)key) != NULL;
+}
+
 int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
                       int len)
 {
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index c3efc33..9c73dad 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -77,32 +77,78 @@
     return (g_log_status == kLogAvailable);
 }
 
+/* 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;
 }
 
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+    int i, ret = 0;
+
+#if FAKE_LOG_DEVICE
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        char buf[sizeof("/dev/log_system")];
+        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+        log_fds[i] = fakeLogOpen(buf, O_WRONLY);
+    }
+#else
+    if (logd_fd >= 0) {
+        i = logd_fd;
+        logd_fd = -1;
+        close(i);
+    }
+
+    i = socket(PF_UNIX, SOCK_DGRAM, 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) {
+            ret = -errno;
+            close(i);
+            i = -1;
+        }
+    }
+    logd_fd = i;
+#endif
+
+    return ret;
+}
+
 static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
 {
-#if FAKE_LOG_DEVICE
     ssize_t ret;
+#if FAKE_LOG_DEVICE
     int log_fd;
 
     if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
         log_fd = log_fds[(int)log_id];
     } else {
-        return EBADF;
+        return -EBADF;
     }
     do {
         ret = fakeLogWritev(log_fd, vec, nr);
-    } while (ret < 0 && errno == EINTR);
+        if (ret < 0) {
+            ret = -errno;
+        }
+    } while (ret == -EINTR);
 
     return ret;
 #else
-    if (logd_fd == -1) {
-        return -1;
-    }
     if (getuid() == AID_LOGD) {
         /*
          * ignore log messages we send to ourself.
@@ -111,11 +157,39 @@
          */
         return 0;
     }
-    struct iovec newVec[nr + 2];
+
+    if (logd_fd < 0) {
+        return -EBADF;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide
+     *      typeof_log_id_t  log_id;
+     *      u16              tid;
+     *      log_time         realtime;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+    static const unsigned header_length = 3;
+    struct iovec newVec[nr + header_length];
     typeof_log_id_t log_id_buf = log_id;
+    uint16_t tid = gettid();
 
     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);
 
     struct timespec ts;
     clock_gettime(CLOCK_REALTIME, &ts);
@@ -123,17 +197,44 @@
     realtime_ts.tv_sec = ts.tv_sec;
     realtime_ts.tv_nsec = ts.tv_nsec;
 
-    newVec[1].iov_base   = (unsigned char *) &realtime_ts;
-    newVec[1].iov_len    = sizeof(log_time);
+    newVec[2].iov_base   = (unsigned char *) &realtime_ts;
+    newVec[2].iov_len    = sizeof(log_time);
 
     size_t i;
-    for (i = 2; i < nr + 2; i++) {
-        newVec[i].iov_base = vec[i-2].iov_base;
-        newVec[i].iov_len  = vec[i-2].iov_len;
+    for (i = header_length; i < nr + header_length; i++) {
+        newVec[i].iov_base = vec[i-header_length].iov_base;
+        newVec[i].iov_len  = vec[i-header_length].iov_len;
     }
 
-    /* The write below could be lost, but will never block. */
-    return writev(logd_fd, newVec, nr + 2);
+    /*
+     * The write below could be lost, but will never block.
+     *
+     * ENOTCONN occurs if logd dies.
+     * EAGAIN occurs if logd is overloaded.
+     */
+    ret = writev(logd_fd, newVec, nr + header_length);
+    if (ret < 0) {
+        ret = -errno;
+        if (ret == -ENOTCONN) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_lock(&log_init_lock);
+#endif
+            ret = __write_to_log_initialize();
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
+#endif
+
+            if (ret < 0) {
+                return ret;
+            }
+
+            ret = writev(logd_fd, newVec, nr + header_length);
+            if (ret < 0) {
+                ret = -errno;
+            }
+        }
+    }
+    return ret;
 #endif
 }
 
@@ -161,35 +262,17 @@
 #endif
 
     if (write_to_log == __write_to_log_init) {
-        write_to_log = __write_to_log_kernel;
+        int ret;
 
-#if FAKE_LOG_DEVICE
-        int i;
-        for (i = 0; i < LOG_ID_MAX; i++) {
-            char buf[sizeof("/dev/log_system")];
-            snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
-            log_fds[i] = fakeLogOpen(buf, O_WRONLY);
-        }
-#else
-        int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
-        if (sock != -1) {
-            if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
-                /* NB: Loss of content */
-                close(sock);
-                sock = -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");
-
-                connect(sock, (struct sockaddr *)&un, sizeof(struct sockaddr_un));
-            }
-        } else {
-            write_to_log = __write_to_log_null;
-        }
-        logd_fd = sock;
+        ret = __write_to_log_initialize();
+        if (ret < 0) {
+#ifdef HAVE_PTHREADS
+            pthread_mutex_unlock(&log_init_lock);
 #endif
+            return ret;
+        }
+
+        write_to_log = __write_to_log_kernel;
     }
 
 #ifdef HAVE_PTHREADS
@@ -219,7 +302,7 @@
         !strcmp(tag, "PHONE") ||
         !strcmp(tag, "SMS")) {
             log_id = LOG_ID_RADIO;
-            // Inform third party apps/ril/radio.. to use Rlog or RLOG
+            /* 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;
     }
@@ -254,7 +337,7 @@
         !strcmp(tag, "PHONE") ||
         !strcmp(tag, "SMS"))) {
             bufID = LOG_ID_RADIO;
-            // Inform third party apps/ril/radio.. to use Rlog or RLOG
+            /* 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;
     }
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 32a202b..5ef349b 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -95,12 +95,15 @@
     if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
         log_fd = log_fds[(int)log_id];
     } else {
-        return EBADF;
+        return -EBADF;
     }
 
     do {
         ret = log_writev(log_fd, vec, nr);
-    } while (ret < 0 && errno == EINTR);
+        if (ret < 0) {
+            ret = -errno;
+        }
+    } while (ret == -EINTR);
 
     return ret;
 }
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index ffb7fd1..d726f2d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -38,30 +38,30 @@
     _rc; })
 
 TEST(liblog, __android_log_buf_print) {
-    ASSERT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "radio"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "system"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "main"));
     usleep(1000);
 }
 
 TEST(liblog, __android_log_buf_write) {
-    ASSERT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "radio"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "system"));
     usleep(1000);
-    ASSERT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "main"));
     usleep(1000);
@@ -69,16 +69,16 @@
 
 TEST(liblog, __android_log_btwrite) {
     int intBuf = 0xDEADBEEF;
-    ASSERT_LT(0, __android_log_btwrite(0,
+    EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_INT,
                                       &intBuf, sizeof(intBuf)));
     long long longBuf = 0xDEADBEEFA55A5AA5;
-    ASSERT_LT(0, __android_log_btwrite(0,
+    EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_LONG,
                                       &longBuf, sizeof(longBuf)));
     usleep(1000);
     char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
-    ASSERT_LT(0, __android_log_btwrite(0,
+    EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_STRING,
                                       Buf, sizeof(Buf) - 1));
     usleep(1000);
@@ -120,7 +120,7 @@
 
     pid_t pid = getpid();
 
-    ASSERT_EQ(0, NULL == (logger_list = android_logger_list_open(
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
 
     log_time ts(CLOCK_MONOTONIC);
@@ -155,7 +155,7 @@
         }
     }
 
-    ASSERT_EQ(1, count);
+    EXPECT_EQ(1, count);
 
     android_logger_list_close(logger_list);
 }
@@ -221,7 +221,7 @@
 
     v += pid & 0xFFFF;
 
-    ASSERT_EQ(0, NULL == (logger_list = android_logger_list_open(
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, O_RDONLY, 1000, pid)));
 
     int count = 0;
@@ -277,13 +277,13 @@
             ++signals;
             break;
         }
-    } while (!signaled || ({log_time t(CLOCK_MONOTONIC); t < signal_time;}));
+    } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
     alarm(0);
     signal(SIGALRM, SIG_DFL);
 
-    ASSERT_LT(1, count);
+    EXPECT_LT(1, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
 
     android_logger_list_close(logger_list);
 
@@ -295,9 +295,245 @@
     const unsigned long long one_percent_ticks = alarm_time;
     unsigned long long user_ticks = uticks_end - uticks_start;
     unsigned long long system_ticks = sticks_end - sticks_start;
-    ASSERT_GT(one_percent_ticks, user_ticks);
-    ASSERT_GT(one_percent_ticks, system_ticks);
-    ASSERT_GT(one_percent_ticks, user_ticks + system_ticks);
+    EXPECT_GT(one_percent_ticks, user_ticks);
+    EXPECT_GT(one_percent_ticks, system_ticks);
+    EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+}
+
+static const char max_payload_tag[] = "TEST_max_payload_XXXX";
+static const char max_payload_buf[LOGGER_ENTRY_MAX_PAYLOAD
+    - sizeof(max_payload_tag) - 1] = "LEONATO\n\
+I learn in this letter that Don Peter of Arragon\n\
+comes this night to Messina\n\
+MESSENGER\n\
+He is very near by this: he was not three leagues off\n\
+when I left him\n\
+LEONATO\n\
+How many gentlemen have you lost in this action?\n\
+MESSENGER\n\
+But few of any sort, and none of name\n\
+LEONATO\n\
+A victory is twice itself when the achiever brings\n\
+home full numbers. I find here that Don Peter hath\n\
+bestowed much honour on a young Florentine called Claudio\n\
+MESSENGER\n\
+Much deserved on his part and equally remembered by\n\
+Don Pedro: he hath borne himself beyond the\n\
+promise of his age, doing, in the figure of a lamb,\n\
+the feats of a lion: he hath indeed better\n\
+bettered expectation than you must expect of me to\n\
+tell you how\n\
+LEONATO\n\
+He hath an uncle here in Messina will be very much\n\
+glad of it.\n\
+MESSENGER\n\
+I have already delivered him letters, and there\n\
+appears much joy in him; even so much that joy could\n\
+not show itself modest enough without a badge of\n\
+bitterness.\n\
+LEONATO\n\
+Did he break out into tears?\n\
+MESSENGER\n\
+In great measure.\n\
+LEONATO\n\
+A kind overflow of kindness: there are no faces\n\
+truer than those that are so washed. How much\n\
+better is it to weep at joy than to joy at weeping!\n\
+BEATRICE\n\
+I pray you, is Signior Mountanto returned from the\n\
+wars or no?\n\
+MESSENGER\n\
+I know none of that name, lady: there was none such\n\
+in the army of any sort.\n\
+LEONATO\n\
+What is he that you ask for, niece?\n\
+HERO\n\
+My cousin means Signior Benedick of Padua.\n\
+MESSENGER\n\
+O, he's returned; and as pleasant as ever he was.\n\
+BEATRICE\n\
+He set up his bills here in Messina and challenged\n\
+Cupid at the flight; and my uncle's fool, reading\n\
+the challenge, subscribed for Cupid, and challenged\n\
+him at the bird-bolt. I pray you, how many hath he\n\
+killed and eaten in these wars? But how many hath\n\
+he killed? for indeed I promised to eat all of his killing.\n\
+LEONATO\n\
+Faith, niece, you tax Signior Benedick too much;\n\
+but he'll be meet with you, I doubt it not.\n\
+MESSENGER\n\
+He hath done good service, lady, in these wars.\n\
+BEATRICE\n\
+You had musty victual, and he hath holp to eat it:\n\
+he is a very valiant trencherman; he hath an\n\
+excellent stomach.\n\
+MESSENGER\n\
+And a good soldier too, lady.\n\
+BEATRICE\n\
+And a good soldier to a lady: but what is he to a lord?\n\
+MESSENGER\n\
+A lord to a lord, a man to a man; stuffed with all\n\
+honourable virtues.\n\
+BEATRICE\n\
+It is so, indeed; he is no less than a stuffed man:\n\
+but for the stuffing,--well, we are all mortal.\n\
+LEONATO\n\
+You must not, sir, mistake my niece. There is a\n\
+kind of merry war betwixt Signior Benedick and her:\n\
+they never meet but there's a skirmish of wit\n\
+between them.\n\
+BEATRICE\n\
+Alas! he gets nothing by that. In our last\n\
+conflict four of his five wits went halting off, and\n\
+now is the whole man governed with one: so that if\n\
+he have wit enough to keep himself warm, let him\n\
+bear it for a difference between himself and his\n\
+horse; for it is all the wealth that he hath left,\n\
+to be known a reasonable creature. Who is his\n\
+companion now? He hath every month a new sworn brother.\n\
+MESSENGER\n\
+Is't possible?\n\
+BEATRICE\n\
+Very easily possible: he wears his faith but as\n\
+the fashion of his hat; it ever changes with the\n\
+next block.\n\
+MESSENGER\n\
+I see, lady, the gentleman is not in your books.\n\
+BEATRICE\n\
+No; an he were, I would burn my study. But, I pray\n\
+you, who is his companion? Is there no young\n\
+squarer now that will make a voyage with him to the devil?\n\
+MESSENGER\n\
+He is most in the company of the right noble Claudio.\n\
+BEATRICE\n\
+O Lord, he will hang upon him like a disease: he\n\
+is sooner caught than the pestilence, and the taker\n\
+runs presently mad. God help the noble Claudio! if\n\
+he have caught the Benedick, it will cost him a\n\
+thousand pound ere a' be cured.\n\
+MESSENGER\n\
+I will hold friends with you, lady.\n\
+BEATRICE\n\
+Do, good friend.\n\
+LEONATO\n\
+You will never run mad, niece.\n\
+BEATRICE\n\
+No, not till a hot January.\n\
+MESSENGER\n\
+Don Pedro is approached.\n\
+Enter DON PEDRO, DON JOHN, CLAUDIO, BENEDICK, and BALTHASAR\n\
+\n\
+DON PEDRO\n\
+Good Signior Leonato, you are come to meet your\n\
+trouble: the fashion of the world is to avoid\n\
+cost, and you encounter it\n\
+LEONATO\n\
+Never came trouble to my house in the likeness";
+
+TEST(liblog, max_payload) {
+    pid_t pid = getpid();
+    char tag[sizeof(max_payload_tag)];
+    memcpy(tag, max_payload_tag, sizeof(tag));
+    snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+
+    LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+                                              tag, max_payload_buf));
+
+    struct logger_list *logger_list;
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SYSTEM, O_RDONLY, 100, 0)));
+
+    bool matches = false;
+    ssize_t max_len = 0;
+
+    for(;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+            continue;
+        }
+
+        char *data = log_msg.msg() + 1;
+
+        if (strcmp(data, tag)) {
+            continue;
+        }
+
+        data += strlen(data) + 1;
+
+        const char *left = data;
+        const char *right = max_payload_buf;
+        while (*left && *right && (*left == *right)) {
+            ++left;
+            ++right;
+        }
+
+        if (max_len <= (left - data)) {
+            max_len = left - data + 1;
+        }
+
+        if (max_len > 512) {
+            matches = true;
+            break;
+        }
+    }
+
+    EXPECT_EQ(true, matches);
+
+    EXPECT_LE(sizeof(max_payload_buf), max_len);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, dual_reader) {
+    struct logger_list *logger_list1;
+
+    // >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)));
+
+    struct logger_list *logger_list2;
+
+    if (NULL == (logger_list2 = android_logger_list_open(
+            LOG_ID_MAIN, O_RDONLY | O_NDELAY, 15, 0))) {
+        android_logger_list_close(logger_list1);
+        ASSERT_TRUE(NULL != logger_list2);
+    }
+
+    int count1 = 0;
+    bool done1 = false;
+    int count2 = 0;
+    bool done2 = false;
+
+    do {
+        log_msg log_msg;
+
+        if (!done1) {
+            if (android_logger_list_read(logger_list1, &log_msg) <= 0) {
+                done1 = true;
+            } else {
+                ++count1;
+            }
+        }
+
+        if (!done2) {
+            if (android_logger_list_read(logger_list2, &log_msg) <= 0) {
+                done2 = true;
+            } else {
+                ++count2;
+            }
+        }
+    } while ((!done1) || (!done2));
+
+    android_logger_list_close(logger_list1);
+    android_logger_list_close(logger_list2);
+
+    EXPECT_EQ(25, count1);
+    EXPECT_EQ(15, count2);
 }
 
 TEST(liblog, android_logger_get_) {
@@ -310,11 +546,11 @@
             continue;
         }
         struct logger * logger;
-        ASSERT_EQ(0, NULL == (logger = android_logger_open(logger_list, id)));
-        ASSERT_EQ(id, android_logger_get_id(logger));
-        ASSERT_LT(0, android_logger_get_log_size(logger));
-        ASSERT_LT(0, android_logger_get_log_readable_size(logger));
-        ASSERT_LT(0, android_logger_get_log_version(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));
+        EXPECT_LT(0, android_logger_get_log_readable_size(logger));
+        EXPECT_LT(0, android_logger_get_log_version(logger));
     }
 
     android_logger_list_close(logger_list);
diff --git a/libnl_2/.gitignore b/libnl_2/.gitignore
deleted file mode 100644
index d4ca744..0000000
--- a/libnl_2/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-include/netlink/version.h.in
-cscope.*
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
deleted file mode 100644
index 3721fc6..0000000
--- a/libnl_2/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-#######################################
-# * Netlink cache not implemented
-# * Library is not thread safe
-#######################################
-
-LOCAL_PATH := $(call my-dir)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        attr.c \
-        cache.c \
-        genl/genl.c \
-        genl/family.c \
-        handlers.c \
-        msg.c \
-        netlink.c \
-        object.c \
-        socket.c \
-        dbg.c
-
-LOCAL_C_INCLUDES += \
-        external/libnl-headers
-
-# Static Library
-LOCAL_MODULE := libnl_2
-LOCAL_MODULE_TAGS := optional
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES :=
-LOCAL_WHOLE_STATIC_LIBRARIES:= libnl_2
-LOCAL_SHARED_LIBRARIES:= liblog
-LOCAL_MODULE := libnl_2
-LOCAL_MODULE_TAGS := optional
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libnl_2/README b/libnl_2/README
deleted file mode 100644
index 14db6db..0000000
--- a/libnl_2/README
+++ /dev/null
@@ -1,88 +0,0 @@
-Netlink Protocol Library
-
-This library is a clean room re-implementation of libnl 2.0 and
-re-licensed under Apache 2.0. It was developed primarily to support
-wpa_supplicant. However, with additional development can be extended
-to support other netlink applications.
-
-Netlink Protocol Format (RFC3549)
-
-+-----------------+-+-------------------+-+
-|Netlink Message  |P| Generic Netlink   |P|
-|    Header       |A|  Message Header   |A|
-|(struct nlmsghdr)|D|(struct genlmsghdr)|D|
-+-----------------+-+-------------------+-+-------------+
-|len:4|type:2|flags:2|seq:4 pid:4|cmd:1|ver:1|reserved:2|
-+--------------------------------+----------------------+
-+-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
-|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|...|
-|    #0 Header    |A|   #0 Payload    |A|   #1 Header     |A|   #1 Payload    |A|   |
-| (struct nlattr) |D|     (void)      |D| (struct nlattr) |D|     (void)      |D|   |
-+-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
-|len:2(==4+payload)|type:2|payload|pad|
-+-------------------------+-------+---+
-
-NETLINK OVERVIEW
-
-* Each netlink message consists of a bitstream with a netlink header.
-* After this header a second header *can* be used specific to the netlink
-  family in use. This library was tested using the generic netlink
-  protocol defined by struct genlmsghdr to support nl80211.
-* After the header(s) netlink attributes can be appended to the message
-  which hold can hold basic types such as unsigned integers and strings.
-* Attributes can also be nested. This is accomplished by calling "nla_nest_start"
-  which creates an empty attribute with nest attributes as its payload. Then to
-  close the nest, "nla_nest_end" is called.
-* All data structures in this implementation are byte-aligned (Currently 4 bytes).
-* Acknowledgements (ACKs) are sent as NLMSG_ERROR netlink message types (0x2) and
-  have an error value of 0.
-
-KNOWN ISSUES
-
-  GENERAL
-  * Not tested for thread safety
-
-  Android.mk
-  * No dynamic library because of netlink cache not implemented and
-    not tested for thread safety
-
-  attr.c
-  * nla_parse - does not use nla_policy argument
-
-  cache.c
-  * netlink cache not implemented and only supports one netlink family id
-    which is stored in the nl_cache pointer instead of an actual cache
-
-  netlink.c
-  * nl_recvmsgs - does not support nl_cb_overwrite_recv()
-  * nl_recv - sets/unsets asynchronous socket flag
-
-SOURCE FILES
-
-* Android.mk - Android makefile
-* README - This file
-* attr.c - Netlink attributes
-* cache.c - Netlink cache
-* genl/family.c - Generic netlink family id
-* genl/genl.c - Generic netlink
-* handlers.c - Netlink callbacks
-* msg.c - Netlink messages construction
-* netlink.c - Netlink socket communication
-* object.c - libnl object wrapper
-* socket.c - Netlink kernel socket utils
-
-IMPORTANT HEADER FILES - NOTE: These are based on the the origin GPL libnl headers
-
-* netlink-types.h - Contains many important structs for libnl
-  to represent netlink objects
-* netlink/netlink-kernel.h - Netlink kernel headers and field constants.
-* netlink/msg.h - macros for iterating over netlink messages
-* netlink/attr.h - netlink attribute constants, iteration macros and setters
-
-REFERENCES
-
-* nl80211.h
-* netlink_types.h
-* $LINUX_KERNEL/net/wireless/nl80211.c
-* http://www.infradead.org/~tgr/libnl/doc-3.0/index.html
-* http://www.netfilter.org/projects/libmnl/doxygen/index.html
diff --git a/libnl_2/attr.c b/libnl_2/attr.c
deleted file mode 100644
index 2ef7590..0000000
--- a/libnl_2/attr.c
+++ /dev/null
@@ -1,239 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include "netlink/netlink.h"
-#include "netlink/msg.h"
-#include "netlink/attr.h"
-#include "netlink-types.h"
-
-/* Return payload of string attribute. */
-char *nla_get_string(struct nlattr *nla)
-{
-	return (char *) nla_data(nla);
-}
-
-/* Return payload of 16 bit integer attribute. */
-uint16_t nla_get_u16(struct nlattr *nla)
-{
-	return *((uint16_t *) nla_data(nla));
-}
-
-/* Return payload of 32 bit integer attribute. */
-uint32_t nla_get_u32(struct nlattr *nla)
-{
-	return *((uint32_t *) nla_data(nla));
-}
-
-/* Return value of 8 bit integer attribute. */
-uint8_t nla_get_u8(struct nlattr *nla)
-{
-	return *((uint8_t *) nla_data(nla));
-}
-
-/* Return payload of uint64_t attribute. */
-uint64_t nla_get_u64(struct nlattr *nla)
-{
-	uint64_t tmp;
-	nla_memcpy(&tmp, nla, sizeof(tmp));
-	return tmp;
-}
-
-/* Head of payload */
-void *nla_data(const struct nlattr *nla)
-{
-	return (void *) ((char *) nla + NLA_HDRLEN);
-}
-
-/* Return length of the payload . */
-int nla_len(const struct nlattr *nla)
-{
-	return nla->nla_len - NLA_HDRLEN;
-}
-
-int nla_padlen(int payload)
-{
-	return NLA_ALIGN(payload) - payload;
-}
-
-/* Start a new level of nested attributes. */
-struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
-{
-	struct nlattr *start = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
-	int rc;
-
-	rc = nla_put(msg, attrtype, 0, NULL);
-	if (rc < 0)
-		return NULL;
-
-	return start;
-}
-
-/* Finalize nesting of attributes. */
-int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
-{
-	/* Set attribute size */
-	start->nla_len = (unsigned char *)nlmsg_tail(nlmsg_hdr(msg)) -
-				(unsigned char *)start;
-	return 0;
-}
-
-/* Return next attribute in a stream of attributes. */
-struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
-{
-	struct nlattr *next_nla = NULL;
-	if (nla->nla_len >= sizeof(struct nlattr) &&
-	   nla->nla_len <= *remaining){
-		next_nla = (struct nlattr *) \
-			((char *) nla + NLA_ALIGN(nla->nla_len));
-		*remaining = *remaining - NLA_ALIGN(nla->nla_len);
-	}
-
-	return next_nla;
-
-}
-
-/* Check if the attribute header and payload can be accessed safely. */
-int nla_ok(const struct nlattr *nla, int remaining)
-{
-	return remaining > 0 &&
-		nla->nla_len >= sizeof(struct nlattr) &&
-		sizeof(struct nlattr) <= (unsigned int) remaining &&
-		nla->nla_len <= remaining;
-}
-
-/* Create attribute index based on a stream of attributes. */
-/* NOTE: Policy not used ! */
-int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
-	int len, struct nla_policy *policy)
-{
-	struct nlattr *pos;
-	int rem;
-
-	/* First clear table */
-	memset(tb, 0, (maxtype + 1) * sizeof(struct nlattr *));
-
-	nla_for_each_attr(pos, head, len, rem) {
-		int type = nla_type(pos);
-
-		if ((type <= maxtype) && (type != 0))
-			tb[type] = pos;
-	}
-
-	return 0;
-}
-
-
-/* Create attribute index based on nested attribute. */
-int nla_parse_nested(struct nlattr *tb[], int maxtype,
-		struct nlattr *nla, struct nla_policy *policy)
-{
-	return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
-}
-
-
-/* Add a unspecific attribute to netlink message. */
-int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
-{
-	struct nlattr *nla;
-
-	/* Reserve space and init nla header */
-	nla = nla_reserve(msg, attrtype, datalen);
-	if (nla) {
-		memcpy(nla_data(nla), data, datalen);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-/* Add 8 bit integer attribute to netlink message. */
-int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint8_t), &value);
-}
-
-/* Add 16 bit integer attribute to netlink message. */
-int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint16_t), &value);
-}
-
-/* Add 32 bit integer attribute to netlink message. */
-int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint32_t), &value);
-}
-
-/* Add 64 bit integer attribute to netlink message. */
-int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
-{
-	return nla_put(msg, attrtype, sizeof(uint64_t), &value);
-}
-
-/* Add nested attributes to netlink message. */
-/* Takes the attributes found in the nested message and appends them
- * to the message msg nested in a container of the type attrtype. The
- * nested message may not have a family specific header */
-int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
-{
-	int rc;
-
-	rc = nla_put(msg, attrtype, nlmsg_attrlen(nlmsg_hdr(nested), 0),
-			nlmsg_attrdata(nlmsg_hdr(nested), 0));
-	return rc;
-
-}
-
-/* Return type of the attribute. */
-int nla_type(const struct nlattr *nla)
-{
-	return (int)nla->nla_type & NLA_TYPE_MASK;
-}
-
-/* Reserves room for an attribute in specified netlink message and fills
- * in the attribute header (type,length). Return NULL if insufficient space */
-struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int data_len)
-{
-
-	struct nlattr *nla;
-	const unsigned int NEW_SIZE = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) +
-					NLA_ALIGN(NLA_HDRLEN + data_len);
-
-	/* Check enough space for attribute */
-	if (NEW_SIZE > msg->nm_size)
-		return NULL;
-
-	nla = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
-	nla->nla_type = attrtype;
-	nla->nla_len = NLA_HDRLEN + data_len;
-	memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(data_len));
-	msg->nm_nlh->nlmsg_len = NEW_SIZE;
-	return nla;
-}
-
-/* Copy attribute payload to another memory area. */
-int nla_memcpy(void *dest, struct nlattr *src, int count)
-{
-	if (!src || !dest)
-		return 0;
-	if (count > nla_len(src))
-		count = nla_len(src);
-	memcpy(dest, nla_data(src), count);
-	return count;
-}
diff --git a/libnl_2/cache.c b/libnl_2/cache.c
deleted file mode 100644
index c21974d..0000000
--- a/libnl_2/cache.c
+++ /dev/null
@@ -1,37 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink/cache.h"
-#include "netlink/object.h"
-
-void nl_cache_free(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_clear(struct nl_cache *cache)
-{
-
-}
-
-void nl_cache_remove(struct nl_object *obj)
-{
-
-}
-
-
diff --git a/libnl_2/dbg.c b/libnl_2/dbg.c
deleted file mode 100644
index 9764de6..0000000
--- a/libnl_2/dbg.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "netlink/netlink.h"
-#include <android/log.h>
-
-void libnl_printf(int level, char *format, ...)
-{
-	va_list ap;
-
-	level = ANDROID_LOG_ERROR;
-	va_start(ap, format);
-	__android_log_vprint(level, "libnl_2", format, ap);
-	va_end(ap);
-}
diff --git a/libnl_2/genl/family.c b/libnl_2/genl/family.c
deleted file mode 100644
index 1beee6e..0000000
--- a/libnl_2/genl/family.c
+++ /dev/null
@@ -1,44 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink-types.h"
-
-static struct genl_family *genl_family_find_byname(const char *name)
-{
-	return NULL;
-}
-
-/* Release reference and none outstanding  */
-void genl_family_put(struct genl_family *family)
-{
-	family->ce_refcnt--;
-	if (family->ce_refcnt <= 0)
-		free(family);
-}
-
-unsigned int genl_family_get_id(struct genl_family *family)
-{
-	const int NO_FAMILY_ID = 0;
-
-	if (!family)
-		return NO_FAMILY_ID;
-	else
-		return family->gf_id;
-
-}
-
diff --git a/libnl_2/genl/genl.c b/libnl_2/genl/genl.c
deleted file mode 100644
index 1a39c6a..0000000
--- a/libnl_2/genl/genl.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *	http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <netlink/genl/ctrl.h>
-#include <netlink/genl/family.h>
-#include "netlink-types.h"
-
-/* Get head of attribute data. */
-struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
-{
-	return (struct nlattr *) \
-		((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
-
-}
-
-/* Get length of attribute data. */
-int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
-{
-	struct nlattr *nla;
-	struct nlmsghdr *nlh;
-
-	nla = genlmsg_attrdata(gnlh, hdrlen);
-	nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
-	return (char *) nlmsg_tail(nlh) - (char *) nla;
-}
-
-/* Add generic netlink header to netlink message. */
-void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
-		int hdrlen, int flags, uint8_t cmd, uint8_t version)
-{
-	int new_size;
-	struct nlmsghdr *nlh;
-	struct timeval tv;
-	struct genlmsghdr *gmh;
-
-	/* Make sure nl_msg has enough space */
-	new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
-	if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
-		goto fail;
-
-	/* Fill in netlink header */
-	nlh = msg->nm_nlh;
-	nlh->nlmsg_len = new_size;
-	nlh->nlmsg_type = family;
-	nlh->nlmsg_pid = getpid();
-	nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
-
-	/* Get current time for sequence number */
-	if (gettimeofday(&tv, NULL))
-		nlh->nlmsg_seq = 1;
-	else
-		nlh->nlmsg_seq = (int) tv.tv_sec;
-
-	/* Setup genlmsghdr in new message */
-	gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
-	gmh->cmd = (__u8) cmd;
-	gmh->version = version;
-
-	return gmh;
-fail:
-	return NULL;
-
-}
-
-/* Socket has already been alloced to connect it to kernel? */
-int genl_connect(struct nl_sock *sk)
-{
-	return nl_connect(sk, NETLINK_GENERIC);
-
-}
-
-int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
-{
-	int rc = -1;
-	int nl80211_genl_id = -1;
-	char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
-	struct nlmsghdr nlmhdr;
-	struct genlmsghdr gmhhdr;
-	struct iovec sendmsg_iov;
-	struct msghdr msg;
-	int num_char;
-	const int RECV_BUF_SIZE = getpagesize();
-	char *recvbuf;
-	struct iovec recvmsg_iov;
-	int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
-	struct nlmsghdr *nlh;
-
-	/* REQUEST GENERIC NETLINK FAMILY ID */
-	/* Message buffer */
-	nlmhdr.nlmsg_len = sizeof(sendbuf);
-	nlmhdr.nlmsg_type = NETLINK_GENERIC;
-	nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
-	nlmhdr.nlmsg_seq = sock->s_seq_next;
-	nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
-
-	/* Generic netlink header */
-	memset(&gmhhdr, 0, sizeof(gmhhdr));
-	gmhhdr.cmd = CTRL_CMD_GETFAMILY;
-	gmhhdr.version = CTRL_ATTR_FAMILY_ID;
-
-	/* Combine netlink and generic netlink headers */
-	memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
-	memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
-
-	/* Create IO vector with Netlink message */
-	sendmsg_iov.iov_base = &sendbuf;
-	sendmsg_iov.iov_len = sizeof(sendbuf);
-
-	/* Socket message */
-	msg.msg_name = (void *) &sock->s_peer;
-	msg.msg_namelen = sizeof(sock->s_peer);
-	msg.msg_iov = &sendmsg_iov;
-	msg.msg_iovlen = 1; /* Only sending one iov */
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_flags = 0;
-
-	/* Send message and verify sent */
-	num_char = sendmsg(sock->s_fd, &msg, 0);
-	if (num_char == -1)
-		return -errno;
-
-	/* RECEIVE GENL CMD RESPONSE */
-
-	/* Create receive iov buffer */
-	recvbuf = (char *) malloc(RECV_BUF_SIZE);
-
-	/* Attach to iov */
-	recvmsg_iov.iov_base = recvbuf;
-	recvmsg_iov.iov_len = RECV_BUF_SIZE;
-
-	msg.msg_iov = &recvmsg_iov;
-	msg.msg_iovlen = 1;
-
-	/***************************************************************/
-	/* Receive message. If multipart message, keep receiving until */
-	/* message type is NLMSG_DONE				       */
-	/***************************************************************/
-
-	do {
-
-		int recvmsg_len, nlmsg_rem;
-
-		/* Receive message */
-		memset(recvbuf, 0, RECV_BUF_SIZE);
-		recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
-
-		/* Make sure receive successful */
-		if (recvmsg_len < 0) {
-			rc = -errno;
-			goto error_recvbuf;
-		}
-
-		/* Parse nlmsghdr */
-		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
-				recvmsg_len, nlmsg_rem) {
-			struct nlattr *nla;
-			int nla_rem;
-
-			/* Check type */
-			switch (nlh->nlmsg_type) {
-			case NLMSG_DONE:
-				goto return_genl_id;
-				break;
-			case NLMSG_ERROR:
-
-				/* Should check nlmsgerr struct received */
-				fprintf(stderr, "Receive message error\n");
-				goto error_recvbuf;
-			case NLMSG_OVERRUN:
-				fprintf(stderr, "Receive data partly lost\n");
-				goto error_recvbuf;
-			case NLMSG_MIN_TYPE:
-			case NLMSG_NOOP:
-				break;
-			default:
-				break;
-			}
-
-
-
-			/* Check flags */
-			if (nlh->nlmsg_flags & NLM_F_MULTI)
-				nlm_f_multi = 1;
-			else
-				nlm_f_multi = 0;
-
-			if (nlh->nlmsg_type & NLMSG_DONE)
-				nlmsg_done = 1;
-			else
-				nlmsg_done = 0;
-
-			/* Iteratve over attributes */
-			nla_for_each_attr(nla,
-					nlmsg_attrdata(nlh, GENL_HDRLEN),
-					nlmsg_attrlen(nlh, GENL_HDRLEN),
-					nla_rem){
-
-				/* If this family is nl80211 */
-				if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
-					!strcmp((char *)nla_data(nla),
-						"nl80211"))
-					nl80211_flag = 1;
-
-				/* Save the family id */
-				else if (nl80211_flag &&
-					nla->nla_type == CTRL_ATTR_FAMILY_ID) {
-					nl80211_genl_id =
-						*((int *)nla_data(nla));
-					nl80211_flag = 0;
-				}
-
-			}
-
-		}
-
-	} while (nlm_f_multi && !nlmsg_done);
-
-return_genl_id:
-	/* Return family id as cache pointer */
-	*result = (struct nl_cache *) nl80211_genl_id;
-	rc = 0;
-error_recvbuf:
-	free(recvbuf);
-error:
-	return rc;
-}
-
-/* Checks the netlink cache to find family reference by name string */
-/* NOTE: Caller needs to call genl_family_put() when done with *
- * returned object */
-struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
-					const char *name)
-{
-	struct genl_family *gf = (struct genl_family *) \
-		malloc(sizeof(struct genl_family));
-	if (!gf)
-		goto fail;
-	memset(gf, 0, sizeof(*gf));
-
-	/* Add ref */
-	gf->ce_refcnt++;
-
-	/* Overriding cache pointer as family id for now */
-	gf->gf_id = (uint16_t) ((uint32_t) cache);
-	strncpy(gf->gf_name, name, GENL_NAMSIZ);
-
-	return gf;
-fail:
-	return NULL;
-
-}
-
-int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
-{
-	struct nl_cache *cache = NULL;
-	struct genl_family *gf = NULL;
-	int id = -1;
-
-	/* Hack to support wpa_supplicant */
-	if (strcmp(name, "nlctrl") == 0)
-		return NETLINK_GENERIC;
-
-	if (strcmp(name, "nl80211") != 0) {
-		fprintf(stderr, "%s is not supported\n", name);
-		return id;
-	}
-
-	if (!genl_ctrl_alloc_cache(sk, &cache)) {
-		gf = genl_ctrl_search_by_name(cache, name);
-		if (gf)
-			id = genl_family_get_id(gf);
-	}
-
-	if (gf)
-		genl_family_put(gf);
-	if (cache)
-		nl_cache_free(cache);
-
-	return id;
-}
diff --git a/libnl_2/handlers.c b/libnl_2/handlers.c
deleted file mode 100644
index 48dcab4..0000000
--- a/libnl_2/handlers.c
+++ /dev/null
@@ -1,90 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <malloc.h>
-#include "netlink-types.h"
-#include "netlink/handlers.h"
-
-/* Allocate a new callback handle. */
-struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
-{
-	struct nl_cb *cb;
-
-	cb = (struct nl_cb *) malloc(sizeof(struct nl_cb));
-	if (cb == NULL)
-		goto fail;
-	memset(cb, 0, sizeof(*cb));
-
-	return nl_cb_get(cb);
-fail:
-	return NULL;
-}
-
-/* Clone an existing callback handle */
-struct nl_cb *nl_cb_clone(struct nl_cb *orig)
-{
-	struct nl_cb *new_cb;
-
-	new_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (new_cb == NULL)
-		goto fail;
-
-	/* Copy original and set refcount to 1 */
-	memcpy(new_cb, orig, sizeof(*orig));
-	new_cb->cb_refcnt = 1;
-
-	return new_cb;
-fail:
-	return NULL;
-}
-
-/* Set up a callback. */
-int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, \
-	nl_recvmsg_msg_cb_t func, void *arg)
-{
-	cb->cb_set[type] = func;
-	cb->cb_args[type] = arg;
-	return 0;
-}
-
-
-
-/* Set up an error callback. */
-int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, \
-	nl_recvmsg_err_cb_t func, void *arg)
-{
-	cb->cb_err = func;
-	cb->cb_err_arg = arg;
-	return 0;
-
-}
-
-struct nl_cb *nl_cb_get(struct nl_cb *cb)
-{
-	cb->cb_refcnt++;
-	return cb;
-}
-
-void nl_cb_put(struct nl_cb *cb)
-{
-	if (!cb)
-		return;
-	cb->cb_refcnt--;
-	if (cb->cb_refcnt <= 0)
-		free(cb);
-}
diff --git a/libnl_2/msg.c b/libnl_2/msg.c
deleted file mode 100644
index 1303e8a..0000000
--- a/libnl_2/msg.c
+++ /dev/null
@@ -1,150 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include "netlink-types.h"
-
-/* Allocate a new netlink message with the default maximum payload size. */
-struct nl_msg *nlmsg_alloc(void)
-{
-	/* Whole page will store nl_msg + nlmsghdr + genlmsghdr + payload */
-	const int page_sz = getpagesize();
-	struct nl_msg *nm;
-	struct nlmsghdr *nlh;
-
-	/* Netlink message */
-	nm = (struct nl_msg *) malloc(page_sz);
-	if (!nm)
-		goto fail;
-
-	/* Netlink message header pointer */
-	nlh = (struct nlmsghdr *) ((char *) nm + sizeof(struct nl_msg));
-
-	/* Initialize */
-	memset(nm, 0, page_sz);
-	nm->nm_size = page_sz;
-
-	nm->nm_src.nl_family = AF_NETLINK;
-	nm->nm_src.nl_pid = getpid();
-
-	nm->nm_dst.nl_family = AF_NETLINK;
-	nm->nm_dst.nl_pid = 0; /* Kernel */
-
-	/* Initialize and add to netlink message */
-	nlh->nlmsg_len = NLMSG_HDRLEN;
-	nm->nm_nlh = nlh;
-
-	/* Add to reference count and return nl_msg */
-	nlmsg_get(nm);
-	return nm;
-fail:
-	return NULL;
-}
-
-/* Return pointer to message payload. */
-void *nlmsg_data(const struct nlmsghdr *nlh)
-{
-	return (char *) nlh + NLMSG_HDRLEN;
-}
-
-/* Add reference count to nl_msg */
-void nlmsg_get(struct nl_msg *nm)
-{
-	nm->nm_refcnt++;
-}
-
-/* Release a reference from an netlink message. */
-void nlmsg_free(struct nl_msg *nm)
-{
-	if (nm) {
-		nm->nm_refcnt--;
-		if (nm->nm_refcnt <= 0)
-			free(nm);
-	}
-
-}
-
-/* Return actual netlink message. */
-struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
-{
-	return n->nm_nlh;
-}
-
-/* Return head of attributes data / payload section */
-struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
-{
-	unsigned char *data = nlmsg_data(nlh);
-	return (struct nlattr *)(data + NLMSG_ALIGN(hdrlen));
-}
-
-/* Returns pointer to end of netlink message */
-void *nlmsg_tail(const struct nlmsghdr *nlh)
-{
-	return (void *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
-}
-
-/* Next netlink message in message stream */
-struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
-{
-	struct nlmsghdr *next_nlh = NULL;
-	int len = nlmsg_len(nlh);
-
-	len = NLMSG_ALIGN(len);
-	if (*remaining > 0 &&
-	    len <= *remaining &&
-	    len >= (int) sizeof(struct nlmsghdr)) {
-		next_nlh = (struct nlmsghdr *)((char *)nlh + len);
-		*remaining -= len;
-	}
-
-	return next_nlh;
-}
-
-int nlmsg_datalen(const struct nlmsghdr *nlh)
-{
-	return nlh->nlmsg_len - NLMSG_HDRLEN;
-}
-
-/* Length of attributes data */
-int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
-{
-	return nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen);
-}
-
-/* Length of netlink message */
-int nlmsg_len(const struct nlmsghdr *nlh)
-{
-	return nlh->nlmsg_len;
-}
-
-/* Check if the netlink message fits into the remaining bytes */
-int nlmsg_ok(const struct nlmsghdr *nlh, int rem)
-{
-	return rem >= (int)sizeof(struct nlmsghdr) &&
-		rem >= nlmsg_len(nlh) &&
-		nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) &&
-		nlmsg_len(nlh) <= (rem);
-}
-
-int nlmsg_padlen(int payload)
-{
-	return NLMSG_ALIGN(payload) - payload;
-}
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
deleted file mode 100644
index ee3d600..0000000
--- a/libnl_2/netlink.c
+++ /dev/null
@@ -1,273 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include "netlink-types.h"
-
-#define NL_BUFFER_SZ (32768U)
-
-/* Checks message for completeness and sends it out */
-int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
-{
-	struct nlmsghdr *nlh = msg->nm_nlh;
-	struct timeval tv;
-
-	if (!nlh) {
-		int errsv = errno;
-		fprintf(stderr, "Netlink message header is NULL!\n");
-		return -errsv;
-	}
-
-	/* Complete the nl_msg header */
-	if (gettimeofday(&tv, NULL))
-		nlh->nlmsg_seq = 1;
-	else
-		nlh->nlmsg_seq = (int) tv.tv_sec;
-	nlh->nlmsg_pid = sk->s_local.nl_pid;
-	nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
-
-	return nl_send(sk, msg);
-}
-
-/* Receives a netlink message, allocates a buffer in *buf and stores
- * the message content. The peer's netlink address is stored in
- * *nla. The caller is responsible for freeing the buffer allocated in
- * *buf if a positive value is returned. Interrupted system calls are
- * handled by repeating the read. The input buffer size is determined
- * by peeking before the actual read is done */
-int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
-	unsigned char **buf, struct ucred **creds)
-{
-	int rc = -1;
-	int sk_flags;
-	int RECV_BUF_SIZE = getpagesize();
-	int errsv;
-	struct iovec recvmsg_iov;
-	struct msghdr msg;
-
-	/* Allocate buffer */
-	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
-	if (!(*buf)) {
-		rc = -ENOMEM;
-		goto fail;
-	}
-
-	/* Prepare to receive message */
-	recvmsg_iov.iov_base = *buf;
-	recvmsg_iov.iov_len = RECV_BUF_SIZE;
-
-	msg.msg_name = (void *) &sk->s_peer;
-	msg.msg_namelen = sizeof(sk->s_peer);
-	msg.msg_iov = &recvmsg_iov;
-	msg.msg_iovlen = 1;
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_flags = 0;
-
-	/* Make non blocking and then restore previous setting */
-	sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
-	fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
-	rc = recvmsg(sk->s_fd, &msg, 0);
-	errsv = errno;
-	fcntl(sk->s_fd, F_SETFL, sk_flags);
-
-	if (rc < 0) {
-		rc = -errsv;
-		free(*buf);
-		*buf = NULL;
-	}
-
-fail:
-	return rc;
-}
-
-/* Receive a set of messages from a netlink socket */
-/* NOTE: Does not currently support callback replacements!!! */
-int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
-{
-	struct sockaddr_nl nla;
-	struct ucred *creds;
-
-	int rc, cb_rc = NL_OK, done = 0;
-
-	do {
-		unsigned char *buf;
-		int i, rem, flags;
-		struct nlmsghdr *nlh;
-		struct nlmsgerr *nlme;
-		struct nl_msg *msg;
-
-		done = 0;
-		rc = nl_recv(sk, &nla, &buf, &creds);
-		if (rc < 0)
-			break;
-
-		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
-
-			if (rc <= 0 || cb_rc == NL_STOP)
-				break;
-
-			/* Check for callbacks */
-
-			msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
-			memset(msg, 0, sizeof(*msg));
-			msg->nm_nlh = nlh;
-
-			/* Check netlink message type */
-
-			switch (msg->nm_nlh->nlmsg_type) {
-			case NLMSG_ERROR:	  /* Used for ACK too */
-				/* Certainly we should be doing some
-				 * checking here to make sure this
-				 * message is intended for us */
-				nlme = nlmsg_data(msg->nm_nlh);
-				if (nlme->error == 0)
-					msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
-
-				rc = nlme->error;
-				cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
-				nlme = NULL;
-				break;
-
-			case NLMSG_DONE:
-				done = 1;
-
-			case NLMSG_OVERRUN:
-			case NLMSG_NOOP:
-			default:
-				break;
-			};
-
-			for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
-
-				if (cb->cb_set[i]) {
-					switch (i) {
-					case NL_CB_VALID:
-						if (rc > 0)
-							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-						break;
-
-					case NL_CB_FINISH:
-						if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
-							(msg->nm_nlh->nlmsg_type & NLMSG_DONE))
-							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-
-						break;
-
-					case NL_CB_ACK:
-						if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
-							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
-
-						break;
-					default:
-						break;
-					}
-				}
-			}
-
-			free(msg);
-			if (done)
-				break;
-		}
-		free(buf);
-		buf = NULL;
-
-		if (done)
-			break;
-	} while (rc > 0 && cb_rc != NL_STOP);
-
-success:
-fail:
-	return rc;
-}
-
-/* Send raw data over netlink socket */
-int nl_send(struct nl_sock *sk, struct nl_msg *msg)
-{
-	struct nlmsghdr *nlh = nlmsg_hdr(msg);
-	struct iovec msg_iov;
-
-	/* Create IO vector with Netlink message */
-	msg_iov.iov_base = nlh;
-	msg_iov.iov_len = nlh->nlmsg_len;
-
-	return nl_send_iovec(sk, msg, &msg_iov, 1);
-}
-
-/* Send netlink message */
-int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
-		   struct iovec *iov, unsigned iovlen)
-{
-	int rc;
-
-	/* Socket message */
-	struct msghdr mh = {
-		.msg_name = (void *) &sk->s_peer,
-		.msg_namelen = sizeof(sk->s_peer),
-		.msg_iov = iov,
-		.msg_iovlen = iovlen,
-		.msg_control = NULL,
-		.msg_controllen = 0,
-		.msg_flags = 0
-	};
-
-	/* Send message and verify sent */
-	rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
-	if (rc < 0)
-		fprintf(stderr, "Error sending netlink message: %d\n", errno);
-	return rc;
-
-}
-
-/* Send netlink message with control over sendmsg() message header */
-int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
-{
-	return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
-}
-
-/* Create and connect netlink socket */
-int nl_connect(struct nl_sock *sk, int protocol)
-{
-	struct sockaddr addr;
-	socklen_t addrlen;
-	int rc;
-
-	/* Create RX socket */
-	sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
-	if (sk->s_fd < 0)
-		return -errno;
-
-	/* Set size of RX and TX buffers */
-	if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
-		return -errno;
-
-	/* Bind RX socket */
-	rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
-		sizeof(sk->s_local));
-	if (rc < 0)
-		return -errno;
-	addrlen = sizeof(addr);
-	getsockname(sk->s_fd, &addr, &addrlen);
-
-	return 0;
-
-}
diff --git a/libnl_2/object.c b/libnl_2/object.c
deleted file mode 100644
index c53accf..0000000
--- a/libnl_2/object.c
+++ /dev/null
@@ -1,33 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include "netlink-types.h"
-
-void nl_object_put(struct nl_object *obj)
-{
-	obj->ce_refcnt--;
-	if (!obj->ce_refcnt)
-		nl_object_free(obj);
-}
-
-void nl_object_free(struct nl_object *obj)
-{
-	nl_cache_remove(obj);
-}
-
-
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
deleted file mode 100644
index f51cf56..0000000
--- a/libnl_2/socket.c
+++ /dev/null
@@ -1,153 +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.
- */
-
-/* NOTICE: This is a clean room re-implementation of libnl */
-
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include "netlink-types.h"
-
-/* Join group */
-int nl_socket_add_membership(struct nl_sock *sk, int group)
-{
-	return setsockopt(sk->s_fd, SOL_NETLINK,
-			NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
-}
-
-/* Allocate new netlink socket. */
-static struct nl_sock *_nl_socket_alloc(void)
-{
-	struct nl_sock *sk;
-	struct timeval tv;
-	struct nl_cb *cb;
-
-	sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
-	if (!sk)
-		return NULL;
-	memset(sk, 0, sizeof(*sk));
-
-	/* Get current time */
-
-	if (gettimeofday(&tv, NULL))
-		goto fail;
-	else
-		sk->s_seq_next = (int) tv.tv_sec;
-
-	/* Create local socket */
-	sk->s_local.nl_family = AF_NETLINK;
-	sk->s_local.nl_pid = 0; /* Kernel fills in pid */
-	sk->s_local.nl_groups = 0; /* No groups */
-
-	/* Create peer socket */
-	sk->s_peer.nl_family = AF_NETLINK;
-	sk->s_peer.nl_pid = 0; /* Kernel */
-	sk->s_peer.nl_groups = 0; /* No groups */
-
-	return sk;
-fail:
-	free(sk);
-	return NULL;
-}
-
-/* Allocate new netlink socket. */
-struct nl_sock *nl_socket_alloc(void)
-{
-	struct nl_sock *sk = _nl_socket_alloc();
-	struct nl_cb *cb;
-
-	if (!sk)
-		return NULL;
-
-	cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (!cb)
-		goto cb_fail;
-	sk->s_cb = cb;
-	return sk;
-cb_fail:
-	free(sk);
-	return NULL;
-}
-
-/* Allocate new socket with custom callbacks. */
-struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
-{
-	struct nl_sock *sk = _nl_socket_alloc();
-
-	if (!sk)
-		return NULL;
-
-	sk->s_cb = cb;
-	nl_cb_get(cb);
-
-	return sk;
-}
-
-/* Free a netlink socket. */
-void nl_socket_free(struct nl_sock *sk)
-{
-	nl_cb_put(sk->s_cb);
-	close(sk->s_fd);
-	free(sk);
-}
-
-/* Sets socket buffer size of netlink socket */
-int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
-{
-	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
-			&rxbuf, (socklen_t) sizeof(rxbuf)))
-		goto error;
-
-	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
-			&txbuf, (socklen_t) sizeof(txbuf)))
-		goto error;
-
-	return 0;
-error:
-	return -errno;
-
-}
-
-int nl_socket_get_fd(struct nl_sock *sk)
-{
-	return sk->s_fd;
-}
-
-void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
-{
-	nl_cb_put(sk->s_cb);
-	sk->s_cb = cb;
-	nl_cb_get(cb);
-}
-
-struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
-{
-	return nl_cb_get(sk->s_cb);
-}
-
-int nl_socket_set_nonblocking(struct nl_sock *sk)
-{
-	if (sk->s_fd == -1)
-		return -NLE_BAD_SOCK;
-
-	if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
-		return -errno;
-
-	return 0;
-}
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index f398a82..385c226 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -109,7 +109,7 @@
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-                refs->stack.dump(LOG_TAG);
+                refs->stack.log(LOG_TAG);
 #endif
                 refs = refs->next;
             }
@@ -123,7 +123,7 @@
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-                refs->stack.dump(LOG_TAG);
+                refs->stack.log(LOG_TAG);
 #endif
                 refs = refs->next;
             }
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 5960609..5a80efe 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -807,7 +807,10 @@
         // squash out the byte count
         cp = buf;
         if (!truncated) {
-            while (isdigit(*cp) || (*cp == '\n')) {
+            while (isdigit(*cp)) {
+                ++cp;
+            }
+            if (*cp == '\n') {
                 ++cp;
             }
         }
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 818a978..0165073 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
 #include <signal.h>
 #include <stdio.h>
+#include <string.h>
+
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/logger.h>
@@ -41,7 +44,7 @@
 TEST(logcat, sorted_order) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
       "r")));
 
@@ -92,34 +95,49 @@
         }
     } last(NULL);
 
+    char *last_buffer = NULL;
     char buffer[5120];
 
     int count = 0;
+    int next_lt_last = 0;
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
             continue;
         }
         if (!last.valid()) {
+            free(last_buffer);
+            last_buffer = strdup(buffer);
             last.init(buffer);
         }
         timestamp next(buffer);
-        ASSERT_EQ(0, next < last);
+        if (next < last) {
+            if (last_buffer) {
+                fprintf(stderr, "<%s", last_buffer);
+            }
+            fprintf(stderr, ">%s", buffer);
+            ++next_lt_last;
+        }
         if (next.valid()) {
+            free(last_buffer);
+            last_buffer = strdup(buffer);
             last.init(buffer);
         }
         ++count;
     }
+    free(last_buffer);
 
     pclose(fp);
 
-    ASSERT_LT(100, count);
+    EXPECT_EQ(0, next_lt_last);
+
+    EXPECT_LT(100, count);
 }
 
 TEST(logcat, buckets) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -d 2>/dev/null",
       "r")));
 
@@ -141,15 +159,15 @@
 
     pclose(fp);
 
-    ASSERT_EQ(15, ids);
+    EXPECT_EQ(15, ids);
 
-    ASSERT_EQ(4, count);
+    EXPECT_EQ(4, count);
 }
 
 TEST(logcat, tail_3) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 3 2>/dev/null",
       "r")));
 
@@ -173,7 +191,7 @@
 TEST(logcat, tail_10) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 10 2>/dev/null",
       "r")));
 
@@ -197,7 +215,7 @@
 TEST(logcat, tail_100) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 100 2>/dev/null",
       "r")));
 
@@ -221,7 +239,7 @@
 TEST(logcat, tail_1000) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -v long -b radio -b events -b system -b main -t 1000 2>/dev/null",
       "r")));
 
@@ -242,6 +260,72 @@
     ASSERT_EQ(1000, count);
 }
 
+TEST(logcat, tail_time) {
+    FILE *fp;
+
+    ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
+
+    char buffer[5120];
+    char *last_timestamp = NULL;
+    char *first_timestamp = NULL;
+    int count = 0;
+    const unsigned int time_length = 18;
+    const unsigned int time_offset = 2;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        if ((buffer[0] == '[') && (buffer[1] == ' ')
+         && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
+         && (buffer[time_offset + 2] == '-')) {
+            ++count;
+            buffer[time_length + time_offset] = '\0';
+            if (!first_timestamp) {
+                first_timestamp = strdup(buffer + time_offset);
+            }
+            free(last_timestamp);
+            last_timestamp = strdup(buffer + time_offset);
+        }
+    }
+    pclose(fp);
+
+    EXPECT_EQ(10, count);
+    EXPECT_TRUE(last_timestamp != NULL);
+    EXPECT_TRUE(first_timestamp != NULL);
+
+    snprintf(buffer, sizeof(buffer), "logcat -v long -b all -t '%s' 2>&1",
+             first_timestamp);
+    ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+
+    int second_count = 0;
+    int last_timestamp_count = -1;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        if ((buffer[0] == '[') && (buffer[1] == ' ')
+         && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
+         && (buffer[time_offset + 2] == '-')) {
+            ++second_count;
+            buffer[time_length + time_offset] = '\0';
+            if (first_timestamp) {
+                // we can get a transitory *extremely* rare failure if hidden
+                // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000
+                EXPECT_STREQ(buffer + time_offset, first_timestamp);
+                free(first_timestamp);
+                first_timestamp = NULL;
+            }
+            if (!strcmp(buffer + time_offset, last_timestamp)) {
+                last_timestamp_count = second_count;
+            }
+        }
+    }
+    pclose(fp);
+
+    free(last_timestamp);
+    last_timestamp = NULL;
+
+    EXPECT_TRUE(first_timestamp == NULL);
+    EXPECT_LE(count, second_count);
+    EXPECT_LE(count, last_timestamp_count);
+}
+
 TEST(logcat, End_to_End) {
     pid_t pid = getpid();
 
@@ -250,7 +334,7 @@
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
 
     FILE *fp;
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b events -t 100 2>/dev/null",
       "r")));
 
@@ -281,7 +365,7 @@
 TEST(logcat, get_) {
     FILE *fp;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -g 2>/dev/null",
       "r")));
 
@@ -329,7 +413,7 @@
 
     v &= 0xFFFFFFFFFFFAFFFFULL;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events 2>&1",
       "r")));
@@ -343,7 +427,6 @@
     signal(SIGALRM, caught_blocking);
     alarm(2);
     while (fgets(buffer, sizeof(buffer), fp)) {
-        alarm(2);
 
         if (!strncmp(buffer, "DONE", 4)) {
             break;
@@ -373,9 +456,9 @@
 
     pclose(fp);
 
-    ASSERT_LE(2, count);
+    EXPECT_LE(2, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
 }
 
 static void caught_blocking_tail(int signum)
@@ -399,7 +482,7 @@
 
     v &= 0xFFFAFFFFFFFFFFFFULL;
 
-    ASSERT_EQ(0, NULL == (fp = popen(
+    ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events -T 5 2>&1",
       "r")));
@@ -413,7 +496,6 @@
     signal(SIGALRM, caught_blocking_tail);
     alarm(2);
     while (fgets(buffer, sizeof(buffer), fp)) {
-        alarm(2);
 
         if (!strncmp(buffer, "DONE", 4)) {
             break;
@@ -445,9 +527,9 @@
 
     pclose(fp);
 
-    ASSERT_LE(2, count);
+    EXPECT_LE(2, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
 }
 
 static void caught_blocking_clear(int signum)
@@ -469,7 +551,7 @@
 
     // This test is racey; an event occurs between clear and dump.
     // We accept that we will get a false positive, but never a false negative.
-    ASSERT_EQ(0, NULL == (fp = popen(
+    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",
@@ -484,7 +566,6 @@
     signal(SIGALRM, caught_blocking_clear);
     alarm(2);
     while (fgets(buffer, sizeof(buffer), fp)) {
-        alarm(2);
 
         if (!strncmp(buffer, "clearLog: ", 10)) {
             fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
@@ -523,9 +604,9 @@
 
     pclose(fp);
 
-    ASSERT_LE(1, count);
+    EXPECT_LE(1, count);
 
-    ASSERT_EQ(1, signals);
+    EXPECT_EQ(1, signals);
 }
 
 #ifdef USERDEBUG_BUILD
@@ -601,22 +682,23 @@
 
     ASSERT_EQ(true, get_white_black(&list));
 
-    static const char adjustment[] = "~! ~1000";
+    static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
     ASSERT_EQ(true, set_white_black(adjustment));
     ASSERT_EQ(true, get_white_black(&adjust));
-    if (strcmp(adjustment, adjust)) {
-        fprintf(stderr, "ERROR: '%s' != '%s'\n", adjustment, adjust);
-    }
-    ASSERT_STREQ(adjustment, adjust);
+    EXPECT_STREQ(adjustment, adjust);
+    free(adjust);
+    adjust = NULL;
+
+    static const char adjustment2[] = "300/20 300/21 2000 ~1000";
+    ASSERT_EQ(true, set_white_black(adjustment2));
+    ASSERT_EQ(true, get_white_black(&adjust));
+    EXPECT_STREQ(adjustment2, adjust);
     free(adjust);
     adjust = NULL;
 
     ASSERT_EQ(true, set_white_black(list));
     ASSERT_EQ(true, get_white_black(&adjust));
-    if (strcmp(list, adjust)) {
-        fprintf(stderr, "ERROR: '%s' != '%s'\n", list, adjust);
-    }
-    ASSERT_STREQ(list, adjust);
+    EXPECT_STREQ(list, adjust);
     free(adjust);
     adjust = NULL;
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 197b7e8..81eb091 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -37,6 +37,8 @@
 LogBuffer::LogBuffer(LastLogTimes *times)
         : mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
+    dgram_qlen_statistics = false;
+
 #ifdef USERDEBUG_BUILD
     log_id_for_each(i) {
         mMaxSize[i] = LOG_BUFFER_SIZE;
@@ -45,13 +47,13 @@
 }
 
 void LogBuffer::log(log_id_t log_id, log_time realtime,
-                    uid_t uid, pid_t pid, const char *msg,
-                    unsigned short len) {
+                    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;
     }
     LogBufferElement *elem = new LogBufferElement(log_id, realtime,
-                                                  uid, pid, msg, len);
+                                                  uid, pid, tid, msg, len);
 
     pthread_mutex_lock(&mLogElementsLock);
 
@@ -61,6 +63,23 @@
     LogBufferElementCollection::iterator last = it;
     while (--it != mLogElements.begin()) {
         if ((*it)->getRealTime() <= realtime) {
+            // halves the peak performance, use with caution
+            if (dgram_qlen_statistics) {
+                LogBufferElementCollection::iterator ib = it;
+                unsigned short buckets, num = 1;
+                for (unsigned short i = 0; (buckets = stats.dgram_qlen(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;
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 0745e56..c3460ca 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -36,6 +36,8 @@
 
     LogStatistics stats;
 
+    bool dgram_qlen_statistics;
+
 #ifdef USERDEBUG_BUILD
     PruneList mPrune;
 
@@ -48,7 +50,8 @@
     LogBuffer(LastLogTimes *times);
 
     void log(log_id_t log_id, log_time realtime,
-             uid_t uid, pid_t pid, const char *msg, unsigned short len);
+             uid_t uid, pid_t pid, pid_t tid,
+             const char *msg, unsigned short len);
     log_time flushTo(SocketClient *writer, const log_time start,
                      bool privileged,
                      bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
@@ -63,6 +66,11 @@
     // *strp uses malloc, use free to release.
     void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
 
+    void enableDgramQlenStatistics() {
+        stats.enableDgramQlenStatistics();
+        dgram_qlen_statistics = true;
+    }
+
 #ifdef USERDEBUG_BUILD
     int initPrune(char *cp) { return mPrune.init(cp); }
     // *strp uses malloc, use free to release.
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 8d45f34..d959ceb 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -27,11 +27,12 @@
 const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0);
 
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
-                                   uid_t uid, pid_t pid, const char *msg,
-                                   unsigned short len)
+                                   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) {
@@ -50,6 +51,7 @@
     entry.len = mMsgLen;
     entry.lid = mLogId;
     entry.pid = mPid;
+    entry.tid = mTid;
     entry.sec = mRealTime.tv_sec;
     entry.nsec = mRealTime.tv_nsec;
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 1da09ae..fdca973 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -26,6 +26,7 @@
     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;
@@ -33,12 +34,14 @@
 
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
-                     uid_t uid, pid_t pid, const char *msg, unsigned short len);
+                     uid_t uid, pid_t pid, pid_t tid,
+                     const char *msg, unsigned short len);
     virtual ~LogBufferElement();
 
     log_id_t getLogId() const { return mLogId; }
     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; }
     log_time getRealTime(void) const { return mRealTime; }
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 2aa2ebb..b835b4f 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -50,7 +50,7 @@
     int socket = cli->getSocket();
 
     ssize_t n = recvmsg(socket, &hdr, 0);
-    if (n <= (ssize_t) sizeof_log_id_t) {
+    if (n <= (ssize_t)(sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time))) {
         return false;
     }
 
@@ -82,17 +82,24 @@
     if (log_id < 0 || log_id >= LOG_ID_MAX) {
         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);
 
-    unsigned short len = n;
+    // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
+    // truncated message to the logs.
+    unsigned short len = n; // cap to internal maximum
     if (len == n) {
-        logbuf->log(log_id, realtime, cred->uid, cred->pid, msg, len);
+        logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg, len);
         reader->notifyNewLog();
     }
 
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 49ee50d..5622ee5 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -275,6 +275,66 @@
         mSizes[i] = 0;
         mElements[i] = 0;
     }
+
+    dgram_qlen_statistics = false;
+    for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) {
+        mMinimum[bucket].tv_sec = (uint32_t)-1;
+        mMinimum[bucket].tv_nsec = 999999999UL;
+    }
+}
+
+//   Each bucket below represents a dgram_qlen of log messages. By
+//   finding the minimum period of time from start to finish
+//   of each dgram_qlen, we can get a performance expectation for
+//   the user space logger. The net result is that the period
+//   of time divided by the dgram_qlen 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 dgram_qlen:
+//       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 dgram_qlen 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::dgram_qlen(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 == LONG_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,
@@ -352,6 +412,9 @@
     log_id_for_each(i) {
         if (logMask & (1 << i)) {
             oldLength = string.length();
+            if (spaces < 0) {
+                spaces = 0;
+            }
             string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
             spaces += spaces_total + oldLength - string.length();
         }
@@ -369,6 +432,9 @@
             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();
@@ -388,12 +454,64 @@
         size_t els = elements(i);
         if (els) {
             oldLength = string.length();
+            if (spaces < 0) {
+                spaces = 0;
+            }
             string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
             spaces -= string.length() - oldLength;
         }
         spaces += spaces_total;
     }
 
+    if (dgram_qlen_statistics) {
+        const unsigned short spaces_time = 6;
+        const unsigned long long max_seconds = 100000;
+        spaces = 0;
+        string.append("\n\nMinimum time between log events per dgram_qlen:\n");
+        for(unsigned short i = 0; dgram_qlen(i); ++i) {
+            oldLength = string.length();
+            if (spaces < 0) {
+                spaces = 0;
+            }
+            string.appendFormat("%*s%u", spaces, "", dgram_qlen(i));
+            spaces += spaces_time + oldLength - string.length();
+        }
+        string.append("\n");
+        spaces = 0;
+        unsigned short n;
+        for(unsigned short i = 0; (n = dgram_qlen(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));
+                } else {
+                    string.appendFormat("%llun", duration);
+                }
+                spaces -= string.length() - oldLength;
+            }
+            spaces += spaces_time;
+        }
+    }
+
     log_id_for_each(i) {
         if (!(logMask & (1 << i))) {
             continue;
@@ -433,7 +551,7 @@
 
             if (!oneline) {
                 first = true;
-            } else if (!first && spaces) {
+            } else if (!first && (spaces > 0)) {
                 string.appendFormat("%*s", spaces, "");
             }
             spaces = 0;
@@ -458,10 +576,16 @@
 
             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;
             }
@@ -502,7 +626,7 @@
                     continue;
                 }
 
-                if (!first && spaces) {
+                if (!first && (spaces > 0)) {
                     string.appendFormat("%*s", spaces, "");
                 }
                 spaces = 0;
@@ -517,10 +641,16 @@
                 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;
@@ -531,7 +661,7 @@
             }
 
             if (gone_els) {
-                if (!first && spaces) {
+                if (!first && (spaces > 0)) {
                     string.appendFormat("%*s", spaces, "");
                 }
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index d44afa2..6a26263 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -114,6 +114,11 @@
     size_t mSizes[LOG_ID_MAX];
     size_t mElements[LOG_ID_MAX];
 
+    bool dgram_qlen_statistics;
+
+    static const unsigned short mBuckets[14];
+    log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
+
 public:
     const log_time start;
 
@@ -121,6 +126,11 @@
 
     LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
 
+    void enableDgramQlenStatistics() { dgram_qlen_statistics = true; }
+    static unsigned short dgram_qlen(unsigned short bucket);
+    unsigned long long minimum(unsigned short bucket);
+    void recordDiff(log_time diff, unsigned short bucket);
+
     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);
 
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index d0ceb9f..5f8173f 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -154,8 +154,8 @@
                 }
                 m = pid - p->mPid;
             }
-            if (m >= 0) {
-                if (m > 0) {
+            if (m <= 0) {
+                if (m < 0) {
                     list->insert(it, new Prune(uid,pid));
                 }
                 break;
diff --git a/logd/main.cpp b/logd/main.cpp
index 6216b95..8792d32 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -24,9 +24,12 @@
 #include <sys/capability.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <linux/prctl.h>
 
+#include <cutils/properties.h>
+
 #include "private/android_filesystem_config.h"
 #include "CommandListener.h"
 #include "LogBuffer.h"
@@ -92,6 +95,12 @@
 
     LogBuffer *logBuf = new LogBuffer(times);
 
+    char dgram_qlen_statistics[PROPERTY_VALUE_MAX];
+    property_get("logd.dgram_qlen.statistics", dgram_qlen_statistics, "");
+    if (atol(dgram_qlen_statistics)) {
+        logBuf->enableDgramQlenStatistics();
+    }
+
     // LogReader listens on /dev/socket/logdr. When a client
     // connects, log entries in the LogBuffer are written to the client.
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 5675cac..6a053b3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -7,6 +7,7 @@
 import /init.environ.rc
 import /init.usb.rc
 import /init.${ro.hardware}.rc
+import /init.${ro.zygote}.rc
 import /init.trace.rc
 
 on early-init
@@ -399,6 +400,11 @@
     start surfaceflinger
     start defaultcrypto
 
+on property:vold.decrypt=trigger_encryption
+    start surfaceflinger
+    start encrypt
+    class_start main
+
 on charger
     class_start charger
 
@@ -442,6 +448,13 @@
     critical
     seclabel u:r:ueventd:s0
 
+service logd /system/bin/logd
+    class core
+    socket logd stream 0666 logd logd
+    socket logdr seqpacket 0666 logd logd
+    socket logdw dgram 0222 logd logd
+    seclabel u:r:logd:s0
+
 service healthd /sbin/healthd
     class core
     critical
@@ -474,12 +487,6 @@
     critical
     socket lmkd seqpacket 0660 system system
 
-service logd /system/bin/logd
-    class main
-    socket logd stream 0666 logd logd
-    socket logdr seqpacket 0666 logd logd
-    socket logdw dgram 0222 logd logd
-
 service servicemanager /system/bin/servicemanager
     class core
     user system
@@ -528,14 +535,6 @@
     group input
     onrestart restart zygote
 
-service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
-    class main
-    socket zygote stream 660 root system
-    onrestart write /sys/android_power/request_state wake
-    onrestart write /sys/power/state on
-    onrestart restart media
-    onrestart restart netd
-
 service drm /system/bin/drmserver
     class main
     user drm
@@ -554,6 +553,13 @@
     # vold will set vold.decrypt to trigger_restart_framework (default
     # encryption) or trigger_restart_min_framework (other encryption)
 
+# One shot invocation to encrypt unencrypted volumes
+service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace
+    disabled
+    oneshot
+    # vold will set vold.decrypt to trigger_restart_framework (default
+    # encryption)
+
 service bootanim /system/bin/bootanimation
     class main
     user graphics
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
new file mode 100644
index 0000000..75961e6
--- /dev/null
+++ b/rootdir/init.zygote32.rc
@@ -0,0 +1,8 @@
+service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
new file mode 100644
index 0000000..afb6d63
--- /dev/null
+++ b/rootdir/init.zygote64.rc
@@ -0,0 +1,8 @@
+service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 9bf17e2..b8fe716 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -35,7 +35,7 @@
 /dev/uhid                 0660   system     net_bt_stack
 /dev/uinput               0660   system     net_bt_stack
 /dev/alarm                0664   system     radio
-/dev/rtc0                 0664   system     radio
+/dev/rtc0                 0640   system     system
 /dev/tty0                 0660   root       system
 /dev/graphics/*           0660   root       graphics
 /dev/msm_hw3dm            0660   system     graphics