Merge "[MIPS64] add atomic-mips64"
diff --git a/adb/adb.c b/adb/adb.c
index 6d3a71b..90bdbaa 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -1344,29 +1344,29 @@
           " unchanged.\n");
     }
 
+    /* add extra groups:
+    ** AID_ADB to access the USB driver
+    ** AID_LOG to read system logs (adb logcat)
+    ** AID_INPUT to diagnose input issues (getevent)
+    ** AID_INET to diagnose network issues (netcfg, ping)
+    ** AID_GRAPHICS to access the frame buffer
+    ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+    ** AID_SDCARD_R to allow reading from the SD card
+    ** AID_SDCARD_RW to allow writing to the SD card
+    ** AID_NET_BW_STATS to read out qtaguid statistics
+    */
+    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
+                       AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+                       AID_NET_BW_STATS };
+    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+        exit(1);
+    }
+
     /* don't listen on a port (default 5037) if running in secure mode */
     /* don't run as root if we are running in secure mode */
     if (should_drop_privileges()) {
         drop_capabilities_bounding_set_if_needed();
 
-        /* add extra groups:
-        ** AID_ADB to access the USB driver
-        ** AID_LOG to read system logs (adb logcat)
-        ** AID_INPUT to diagnose input issues (getevent)
-        ** AID_INET to diagnose network issues (netcfg, ping)
-        ** AID_GRAPHICS to access the frame buffer
-        ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
-        ** AID_SDCARD_R to allow reading from the SD card
-        ** AID_SDCARD_RW to allow writing to the SD card
-        ** AID_NET_BW_STATS to read out qtaguid statistics
-        */
-        gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
-                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
-                           AID_NET_BW_STATS };
-        if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-            exit(1);
-        }
-
         /* then switch user and group to "shell" */
         if (setgid(AID_SHELL) != 0) {
             exit(1);
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index fa7fd98..8cbe840 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -61,7 +61,7 @@
     int w, h, f;
     int fds[2];
 
-    if (pipe(fds) < 0) goto pipefail;
+    if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
 
     pid_t pid = fork();
     if (pid < 0) goto done;
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index c7e0ad5..e7d8268 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -74,6 +74,8 @@
 #define VENDOR_ID_GIGABYTE      0x0414
 // Gigaset's USB Vendor ID
 #define VENDOR_ID_GIGASET       0x1E85
+// GIONEE's USB Vendor ID
+#define VENDOR_ID_GIONEE        0x271D
 // Google's USB Vendor ID
 #define VENDOR_ID_GOOGLE        0x18d1
 // Haier's USB Vendor ID
@@ -82,6 +84,8 @@
 #define VENDOR_ID_HARRIS        0x19A5
 // Hisense's USB Vendor ID
 #define VENDOR_ID_HISENSE       0x109b
+// Honeywell's USB Vendor ID
+#define VENDOR_ID_HONEYWELL     0x0c2e
 // HP's USB Vendor ID
 #define VENDOR_ID_HP            0x03f0
 // HTC's USB Vendor ID
@@ -210,10 +214,12 @@
     VENDOR_ID_GARMIN_ASUS,
     VENDOR_ID_GIGABYTE,
     VENDOR_ID_GIGASET,
+    VENDOR_ID_GIONEE,
     VENDOR_ID_GOOGLE,
     VENDOR_ID_HAIER,
     VENDOR_ID_HARRIS,
     VENDOR_ID_HISENSE,
+    VENDOR_ID_HONEYWELL,
     VENDOR_ID_HP,
     VENDOR_ID_HTC,
     VENDOR_ID_HUAWEI,
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 8be3541..e4d7ecc 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -3,24 +3,24 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	backtrace.cpp \
-	debuggerd.cpp \
-	getevent.cpp \
-	tombstone.cpp \
-	utility.cpp \
+    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_mips64 := 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
+LOCAL_CPPFLAGS := \
+    -std=gnu++11 \
+    -W -Wall -Wextra \
+    -Wunused \
+    -Werror \
 
 ifeq ($(ARCH_ARM_HAVE_VFP),true)
 LOCAL_CFLAGS_arm += -DWITH_VFP
@@ -30,11 +30,10 @@
 endif # ARCH_ARM_HAVE_VFP_D32
 
 LOCAL_SHARED_LIBRARIES := \
-	libbacktrace \
-	libc \
-	libcutils \
-	liblog \
-	libselinux \
+    libbacktrace \
+    libcutils \
+    liblog \
+    libselinux \
 
 include external/stlport/libstlport.mk
 
@@ -42,6 +41,7 @@
 LOCAL_MODULE_STEM_32 := debuggerd
 LOCAL_MODULE_STEM_64 := debuggerd64
 LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 include $(BUILD_EXECUTABLE)
 
@@ -50,6 +50,7 @@
 LOCAL_SRC_FILES_arm    := arm/crashglue.S
 LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
 LOCAL_SRC_FILES_mips   := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips/crashglue.S
 LOCAL_SRC_FILES_x86    := x86/crashglue.S
 LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index fd2f69b..839d47a 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -40,57 +40,55 @@
 
 // If configured to do so, dump memory around *all* registers
 // for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
   struct pt_regs regs;
   if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
     return;
   }
 
-  if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
-    static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
+  static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
 
-    for (int reg = 0; reg < 14; reg++) {
-      // this may not be a valid way to access, but it'll do for now
-      uintptr_t addr = regs.uregs[reg];
+  for (int reg = 0; reg < 14; reg++) {
+    // this may not be a valid way to access, but it'll do for now
+    uintptr_t addr = regs.uregs[reg];
 
-      // Don't bother if it looks like a small int or ~= null, or if
-      // it's in the kernel area.
-      if (addr < 4096 || addr >= 0xc0000000) {
-        continue;
-      }
-
-      _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-      dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+    // Don't bother if it looks like a small int or ~= null, or if
+    // it's in the kernel area.
+    if (addr < 4096 || addr >= 0xc0000000) {
+      continue;
     }
+
+    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+    dump_memory(log, tid, addr);
   }
 
   // explicitly allow upload of code dump logging
-  _LOG(log, scope_flags, "\ncode around pc:\n");
-  dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags);
+  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+  dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
 
   if (regs.ARM_pc != regs.ARM_lr) {
-    _LOG(log, scope_flags, "\ncode around lr:\n");
-    dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags);
+    _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
+    dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
   }
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
   struct pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  _LOG(log, scope_flags, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+  _LOG(log, logtype::REGISTERS, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
        static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
        static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
-  _LOG(log, scope_flags, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+  _LOG(log, logtype::REGISTERS, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
        static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
        static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
-  _LOG(log, scope_flags, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
+  _LOG(log, logtype::REGISTERS, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
        static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
        static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
-  _LOG(log, scope_flags, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
+  _LOG(log, logtype::REGISTERS, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
        static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
        static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
        static_cast<uint32_t>(r.ARM_cpsr));
@@ -100,14 +98,14 @@
   int i;
 
   if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
   for (i = 0; i < NUM_VFP_REGS; i += 2) {
-    _LOG(log, scope_flags, "    d%-2d %016llx  d%-2d %016llx\n",
+    _LOG(log, logtype::REGISTERS, "    d%-2d %016llx  d%-2d %016llx\n",
          i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
   }
-  _LOG(log, scope_flags, "    scr %08lx\n", vfp_regs.fpscr);
+  _LOG(log, logtype::REGISTERS, "    scr %08lx\n", vfp_regs.fpscr);
 #endif
 }
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 2413d5e..48308c3 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -37,68 +37,66 @@
  * If configured to do so, dump memory around *all* registers
  * for the crashing thread.
  */
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
     struct user_pt_regs regs;
     struct iovec io;
     io.iov_base = &regs;
     io.iov_len = sizeof(regs);
 
     if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
-        _LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n",
+        _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
              __func__, strerror(errno));
         return;
     }
 
-    if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
-        for (int reg = 0; reg < 31; reg++) {
-            uintptr_t addr = regs.regs[reg];
+    for (int reg = 0; reg < 31; reg++) {
+        uintptr_t addr = regs.regs[reg];
 
-            /*
-             * Don't bother if it looks like a small int or ~= null, or if
-             * it's in the kernel area.
-             */
-            if (addr < 4096 || addr >= (1UL<<63)) {
-                continue;
-            }
-
-            _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg);
-            dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+        /*
+         * Don't bother if it looks like a small int or ~= null, or if
+         * it's in the kernel area.
+         */
+        if (addr < 4096 || addr >= (1UL<<63)) {
+            continue;
         }
+
+        _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
+        dump_memory(log, tid, addr);
     }
 
-    _LOG(log, scope_flags, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags);
+    _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)regs.pc);
 
     if (regs.pc != regs.sp) {
-        _LOG(log, scope_flags, "\ncode around sp:\n");
-        dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags);
+        _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
+        dump_memory(log, tid, (uintptr_t)regs.sp);
     }
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags)
-{
+void dump_registers(log_t* log, pid_t tid) {
   struct user_pt_regs r;
   struct iovec io;
   io.iov_base = &r;
   io.iov_len = sizeof(r);
 
   if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
-    _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
     return;
   }
 
   for (int i = 0; i < 28; i += 4) {
-    _LOG(log, scope_flags, "    x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx\n",
+    _LOG(log, logtype::REGISTERS,
+         "    x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx\n",
          i, (uint64_t)r.regs[i],
          i+1, (uint64_t)r.regs[i+1],
          i+2, (uint64_t)r.regs[i+2],
          i+3, (uint64_t)r.regs[i+3]);
   }
 
-  _LOG(log, scope_flags, "    x28  %016lx  x29  %016lx  x30  %016lx\n",
+  _LOG(log, logtype::REGISTERS, "    x28  %016lx  x29  %016lx  x30  %016lx\n",
        (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
 
-  _LOG(log, scope_flags, "    sp   %016lx  pc   %016lx\n",
+  _LOG(log, logtype::REGISTERS, "    sp   %016lx  pc   %016lx\n",
        (uint64_t)r.sp, (uint64_t)r.pc);
 
 
@@ -107,12 +105,12 @@
   io.iov_len = sizeof(f);
 
   if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
-    _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
     return;
   }
 
   for (int i = 0; i < 32; i += 4) {
-    _LOG(log, scope_flags, "    v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx\n",
          i, (uint64_t)f.vregs[i],
          i+1, (uint64_t)f.vregs[i+1],
          i+2, (uint64_t)f.vregs[i+2],
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index d388348..50bc167 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -30,6 +30,7 @@
 #include <UniquePtr.h>
 
 #include "backtrace.h"
+
 #include "utility.h"
 
 static void dump_process_header(log_t* log, pid_t pid) {
@@ -49,15 +50,15 @@
   localtime_r(&t, &tm);
   char timestr[64];
   strftime(timestr, sizeof(timestr), "%F %T", &tm);
-  _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
+  _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
 
   if (procname) {
-    _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
+    _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
   }
 }
 
 static void dump_process_footer(log_t* log, pid_t pid) {
-  _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
+  _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
 }
 
 static void dump_thread(
@@ -79,10 +80,10 @@
     }
   }
 
-  _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+  _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
 
   if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
-    _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
+    _LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno));
     return;
   }
 
@@ -90,11 +91,11 @@
 
   UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
   if (backtrace->Unwind(0)) {
-    dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, "  ");
+    dump_backtrace_to_log(backtrace.get(), log, "  ");
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
-    LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
+    _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", tid, strerror(errno));
     *detach_failed = true;
   }
 }
@@ -104,7 +105,6 @@
   log_t log;
   log.tfd = fd;
   log.amfd = amfd;
-  log.quiet = true;
 
   dump_process_header(&log, pid);
   dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
@@ -133,9 +133,8 @@
   dump_process_footer(&log, pid);
 }
 
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
-                           int scope_flags, const char* prefix) {
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
   for (size_t i = 0; i < backtrace->NumFrames(); i++) {
-    _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
   }
 }
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 2ec8afb..da14cd4 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -29,7 +29,6 @@
                     int* total_sleep_time_usec);
 
 /* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
-                           int scope_flags, const char* prefix);
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 4721da9..e11d9af 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -110,12 +110,19 @@
     free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
 }
 
+static void sigsegv_non_null() {
+    int* a = (int *)(&do_action);
+    *a = 42;
+}
+
 static int do_action(const char* arg)
 {
     fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
 
     if (!strncmp(arg, "thread-", strlen("thread-"))) {
         return do_action_on_thread(arg + strlen("thread-"));
+    } else if (!strcmp(arg, "SIGSEGV-non-null")) {
+        sigsegv_non_null();
     } else if (!strcmp(arg, "smash-stack")) {
         return smash_stack(42);
     } else if (!strcmp(arg, "stack-overflow")) {
@@ -166,7 +173,8 @@
     fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  SIGPIPE               cause a SIGPIPE\n");
-    fprintf(stderr, "  SIGSEGV               cause a SIGSEGV (synonym: crash)\n");
+    fprintf(stderr, "  SIGSEGV               cause a SIGSEGV at address 0x0 (synonym: crash)\n");
+    fprintf(stderr, "  SIGSEGV-non-null      cause a SIGSEGV at a non-zero address\n");
     fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\n");
     fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
     fprintf(stderr, "on the process' main thread.\n");
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 3726c38..ac0c36b 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -30,7 +30,6 @@
 #include <sys/stat.h>
 #include <sys/poll.h>
 
-#include <log/logd.h>
 #include <log/logger.h>
 
 #include <cutils/sockets.h>
@@ -62,7 +61,7 @@
   char exe[PATH_MAX];
   int count;
   if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
-    LOG("readlink('%s') failed: %s", path, strerror(errno));
+    ALOGE("readlink('%s') failed: %s", path, strerror(errno));
     strlcpy(exe, "unknown", sizeof(exe));
   } else {
     exe[count] = '\0';
@@ -79,17 +78,17 @@
   }
 
   // Explain how to attach the debugger.
-  LOG(    "********************************************************\n"
-          "* Process %d has been suspended while crashing.\n"
-          "* To attach gdbserver for a gdb connection on port 5039\n"
-          "* and start gdbclient:\n"
-          "*\n"
-          "*     gdbclient %s :5039 %d\n"
-          "*\n"
-          "* Wait for gdb to start, then press the VOLUME DOWN key\n"
-          "* to let the process continue crashing.\n"
-          "********************************************************\n",
-          pid, name, pid);
+  ALOGI("********************************************************\n"
+        "* Process %d has been suspended while crashing.\n"
+        "* To attach gdbserver for a gdb connection on port 5039\n"
+        "* and start gdbclient:\n"
+        "*\n"
+        "*     gdbclient %s :5039 %d\n"
+        "*\n"
+        "* Wait for gdb to start, then press the VOLUME DOWN key\n"
+        "* to let the process continue crashing.\n"
+        "********************************************************\n",
+        pid, name, pid);
 
   // Wait for VOLUME DOWN.
   if (init_getevent() == 0) {
@@ -104,7 +103,7 @@
     uninit_getevent();
   }
 
-  LOG("debuggerd resuming process %d", pid);
+  ALOGI("debuggerd resuming process %d", pid);
 }
 
 static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
@@ -140,11 +139,11 @@
   socklen_t len = sizeof(cr);
   int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
   if (status != 0) {
-    LOG("cannot get credentials\n");
+    ALOGE("cannot get credentials\n");
     return -1;
   }
 
-  XLOG("reading tid\n");
+  ALOGV("reading tid\n");
   fcntl(fd, F_SETFL, O_NONBLOCK);
 
   pollfd pollfds[1];
@@ -153,7 +152,7 @@
   pollfds[0].revents = 0;
   status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
   if (status != 1) {
-    LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
+    ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
     return -1;
   }
 
@@ -161,14 +160,11 @@
   memset(&msg, 0, sizeof(msg));
   status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
   if (status < 0) {
-    LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
+    ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
     return -1;
   }
-  if (status == sizeof(debugger_msg_t)) {
-    XLOG("crash request of size %d abort_msg_address=0x%" PRIPTR "\n",
-         status, msg.abort_msg_address);
-  } else {
-    LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
+  if (status != sizeof(debugger_msg_t)) {
+    ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
     return -1;
   }
 
@@ -186,7 +182,7 @@
     struct stat s;
     snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
     if (stat(buf, &s)) {
-      LOG("tid %d does not exist in pid %d. ignoring debug request\n",
+      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
           out_request->tid, out_request->pid);
       return -1;
     }
@@ -197,7 +193,7 @@
     status = get_process_info(out_request->tid, &out_request->pid,
                               &out_request->uid, &out_request->gid);
     if (status < 0) {
-      LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
+      ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
       return -1;
     }
   } else {
@@ -218,13 +214,13 @@
 }
 
 static void handle_request(int fd) {
-  XLOG("handle_request(%d)\n", fd);
+  ALOGV("handle_request(%d)\n", fd);
 
   debugger_request_t request;
   memset(&request, 0, sizeof(request));
   int status = read_request(fd, &request);
   if (!status) {
-    XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
+    ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
          request.pid, request.uid, request.gid, request.tid);
 
     // At this point, the thread that made the request is blocked in
@@ -238,12 +234,12 @@
     // See details in bionic/libc/linker/debugger.c, in function
     // debugger_signal_handler().
     if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
-      LOG("ptrace attach failed: %s\n", strerror(errno));
+      ALOGE("ptrace attach failed: %s\n", strerror(errno));
     } else {
       bool detach_failed = false;
       bool attach_gdb = should_attach_gdb(&request);
       if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
-        LOG("failed responding to client: %s\n", strerror(errno));
+        ALOGE("failed responding to client: %s\n", strerror(errno));
       } else {
         char* tombstone_path = NULL;
 
@@ -262,20 +258,20 @@
           switch (signal) {
             case SIGSTOP:
               if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-                XLOG("stopped -- dumping to tombstone\n");
+                ALOGV("stopped -- dumping to tombstone\n");
                 tombstone_path = engrave_tombstone(request.pid, request.tid,
                                                    signal, request.original_si_code,
-                                                   request.abort_msg_address, true, true,
+                                                   request.abort_msg_address, true,
                                                    &detach_failed, &total_sleep_time_usec);
               } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
-                XLOG("stopped -- dumping to fd\n");
+                ALOGV("stopped -- dumping to fd\n");
                 dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
                                &total_sleep_time_usec);
               } else {
-                XLOG("stopped -- continuing\n");
+                ALOGV("stopped -- continuing\n");
                 status = ptrace(PTRACE_CONT, request.tid, 0, 0);
                 if (status) {
-                  LOG("ptrace continue failed: %s\n", strerror(errno));
+                  ALOGE("ptrace continue failed: %s\n", strerror(errno));
                 }
                 continue; // loop again
               }
@@ -291,7 +287,7 @@
             case SIGSTKFLT:
 #endif
             case SIGTRAP:
-              XLOG("stopped -- fatal signal\n");
+              ALOGV("stopped -- fatal signal\n");
               // Send a SIGSTOP to the process to make all of
               // the non-signaled threads stop moving.  Without
               // this we get a lot of "ptrace detach failed:
@@ -301,13 +297,12 @@
               // makes the process less reliable, apparently...
               tombstone_path = engrave_tombstone(request.pid, request.tid,
                                                  signal, request.original_si_code,
-                                                 request.abort_msg_address, !attach_gdb, false,
+                                                 request.abort_msg_address, !attach_gdb,
                                                  &detach_failed, &total_sleep_time_usec);
               break;
 
             default:
-              XLOG("stopped -- unexpected signal\n");
-              LOG("process stopped due to unexpected signal %d\n", signal);
+              ALOGE("process stopped due to unexpected signal %d\n", signal);
               break;
           }
           break;
@@ -323,14 +318,14 @@
         free(tombstone_path);
       }
 
-      XLOG("detaching\n");
+      ALOGV("detaching\n");
       if (attach_gdb) {
         // stop the process so we can debug
         kill(request.pid, SIGSTOP);
 
         // detach so we can attach gdbserver
         if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-          LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+          ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
           detach_failed = true;
         }
 
@@ -342,7 +337,7 @@
       } else {
         // just detach
         if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-          LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+          ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
           detach_failed = true;
         }
       }
@@ -354,7 +349,7 @@
       // actual parent won't receive a death notification via wait(2).  At this point
       // there's not much we can do about that.
       if (detach_failed) {
-        LOG("debuggerd committing suicide to free the zombie!\n");
+        ALOGE("debuggerd committing suicide to free the zombie!\n");
         kill(getpid(), SIGKILL);
       }
     }
@@ -400,16 +395,16 @@
     return 1;
   fcntl(s, F_SETFD, FD_CLOEXEC);
 
-  LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
+  ALOGI("debuggerd: " __DATE__ " " __TIME__ "\n");
 
   for (;;) {
     sockaddr addr;
     socklen_t alen = sizeof(addr);
 
-    XLOG("waiting for connection\n");
+    ALOGV("waiting for connection\n");
     int fd = accept(s, &addr, &alen);
     if (fd < 0) {
-      XLOG("accept failed: %s\n", strerror(errno));
+      ALOGV("accept failed: %s\n", strerror(errno));
       continue;
     }
 
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index 2f1e201..fca9fbe 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -21,7 +21,7 @@
 
 #include "utility.h"
 
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags);
-void dump_registers(log_t* log, pid_t tid, int scope_flags);
+void dump_memory_and_code(log_t* log, pid_t tid);
+void dump_registers(log_t* log, pid_t tid);
 
 #endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index 5c82d4d..97834c7 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -27,9 +27,6 @@
 #include "../utility.h"
 #include "../machine.h"
 
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
 #define R(x) (static_cast<unsigned int>(x))
 
 // The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS
@@ -46,72 +43,70 @@
 
 // If configured to do so, dump memory around *all* registers
 // for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
   pt_regs_mips_t r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
     return;
   }
 
-  if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
-    static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+  static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
 
-    for (int reg = 0; reg < 32; reg++) {
-      // skip uninteresting registers
-      if (reg == 0 // $0
-          || reg == 26 // $k0
-          || reg == 27 // $k1
-          || reg == 31 // $ra (done below)
-         )
-        continue;
+  for (int reg = 0; reg < 32; reg++) {
+    // skip uninteresting registers
+    if (reg == 0 // $0
+        || reg == 26 // $k0
+        || reg == 27 // $k1
+        || reg == 31 // $ra (done below)
+       )
+      continue;
 
-      uintptr_t addr = R(r.regs[reg]);
+    uintptr_t addr = R(r.regs[reg]);
 
-      // Don't bother if it looks like a small int or ~= null, or if
-      // it's in the kernel area.
-      if (addr < 4096 || addr >= 0x80000000) {
-        continue;
-      }
-
-      _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-      dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+    // Don't bother if it looks like a small int or ~= null, or if
+    // it's in the kernel area.
+    if (addr < 4096 || addr >= 0x80000000) {
+      continue;
     }
+
+    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+    dump_memory(log, tid, addr);
   }
 
   unsigned int pc = R(r.cp0_epc);
   unsigned int ra = R(r.regs[31]);
 
-  _LOG(log, scope_flags, "\ncode around pc:\n");
-  dump_memory(log, tid, (uintptr_t)pc, scope_flags);
+  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+  dump_memory(log, tid, (uintptr_t)pc);
 
   if (pc != ra) {
-    _LOG(log, scope_flags, "\ncode around ra:\n");
-    dump_memory(log, tid, (uintptr_t)ra, scope_flags);
+    _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
+    dump_memory(log, tid, (uintptr_t)ra);
   }
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
   pt_regs_mips_t r;
   if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  _LOG(log, scope_flags, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
+  _LOG(log, logtype::REGISTERS, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
        R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
-  _LOG(log, scope_flags, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
        R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
-  _LOG(log, scope_flags, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
        R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
-  _LOG(log, scope_flags, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
+  _LOG(log, logtype::REGISTERS, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
        R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
-  _LOG(log, scope_flags, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
        R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
-  _LOG(log, scope_flags, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
+  _LOG(log, logtype::REGISTERS, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
        R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
-  _LOG(log, scope_flags, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
+  _LOG(log, logtype::REGISTERS, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
        R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
-  _LOG(log, scope_flags, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
+  _LOG(log, logtype::REGISTERS, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
        R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
-  _LOG(log, scope_flags, " hi %08x  lo %08x bva %08x epc %08x\n",
+  _LOG(log, logtype::REGISTERS, " hi %08x  lo %08x bva %08x epc %08x\n",
        R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
 }
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index cdaa09f..7482886 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -56,6 +58,21 @@
 // Must match the path defined in NativeCrashListener.java
 #define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
 
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__)
+#define ABI_STRING "mips"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#else
+#error "Unsupported ABI"
+#endif
+
 static bool signal_has_si_addr(int sig) {
   switch (sig) {
     case SIGBUS:
@@ -157,27 +174,23 @@
   return "?";
 }
 
-static void dump_revision_info(log_t* log) {
+static void dump_header_info(log_t* log) {
+  char fingerprint[PROPERTY_VALUE_MAX];
   char revision[PROPERTY_VALUE_MAX];
 
+  property_get("ro.build.fingerprint", fingerprint, "unknown");
   property_get("ro.revision", revision, "unknown");
 
-  _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
-}
-
-static void dump_build_info(log_t* log) {
-  char fingerprint[PROPERTY_VALUE_MAX];
-
-  property_get("ro.build.fingerprint", fingerprint, "unknown");
-
-  _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
+  _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
+  _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
+  _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
 static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
-    _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
+    _LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno));
     return;
   }
 
@@ -191,11 +204,11 @@
     snprintf(addr_desc, sizeof(addr_desc), "--------");
   }
 
-  _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %s\n",
+  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
        signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
 }
 
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
   char path[64];
   char threadnamebuf[1024];
   char* threadname = NULL;
@@ -213,25 +226,21 @@
     }
   }
 
-  if (IS_AT_FAULT(scope_flags)) {
-    char procnamebuf[1024];
-    char* procname = NULL;
+  char procnamebuf[1024];
+  char* procname = NULL;
 
-    snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
-    if ((fp = fopen(path, "r"))) {
-      procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
-      fclose(fp);
-    }
-
-    _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
-         threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
-  } else {
-    _LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN");
+  snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+  if ((fp = fopen(path, "r"))) {
+    procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
+    fclose(fp);
   }
+
+  _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
+       threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
 }
 
 static void dump_stack_segment(
-    Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
+    Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
   for (size_t i = 0; i < words; i++) {
     word_t stack_content;
     if (!backtrace->ReadWord(*sp, &stack_content)) {
@@ -250,27 +259,27 @@
     if (!func_name.empty()) {
       if (!i && label >= 0) {
         if (offset) {
-          _LOG(log, scope_flags, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
+          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
                label, *sp, stack_content, map_name, func_name.c_str(), offset);
         } else {
-          _LOG(log, scope_flags, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
+          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
                label, *sp, stack_content, map_name, func_name.c_str());
         }
       } else {
         if (offset) {
-          _LOG(log, scope_flags, "         %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
+          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
                *sp, stack_content, map_name, func_name.c_str(), offset);
         } else {
-          _LOG(log, scope_flags, "         %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
+          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
                *sp, stack_content, map_name, func_name.c_str());
         }
       }
     } else {
       if (!i && label >= 0) {
-        _LOG(log, scope_flags, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s\n",
+        _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s\n",
              label, *sp, stack_content, map_name);
       } else {
-        _LOG(log, scope_flags, "         %" PRIPTR "  %" PRIPTR "  %s\n",
+        _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s\n",
              *sp, stack_content, map_name);
       }
     }
@@ -279,7 +288,7 @@
   }
 }
 
-static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_stack(Backtrace* backtrace, log_t* log) {
   size_t first = 0, last;
   for (size_t i = 0; i < backtrace->NumFrames(); i++) {
     const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
@@ -295,27 +304,22 @@
   }
   first--;
 
-  scope_flags |= SCOPE_SENSITIVE;
-
   // Dump a few words before the first frame.
   word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
-  dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
+  dump_stack_segment(backtrace, log, &sp, STACK_WORDS, -1);
 
   // Dump a few words from all successive frames.
   // Only log the first 3 frames, put the rest in the tombstone.
   for (size_t i = first; i <= last; i++) {
     const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
     if (sp != frame->sp) {
-      _LOG(log, scope_flags, "         ........  ........\n");
+      _LOG(log, logtype::STACK, "         ........  ........\n");
       sp = frame->sp;
     }
-    if (i - first == 3) {
-      scope_flags &= (~SCOPE_AT_FAULT);
-    }
     if (i == last) {
-      dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+      dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
       if (sp < frame->sp + frame->stack_size) {
-        _LOG(log, scope_flags, "         ........  ........\n");
+        _LOG(log, logtype::STACK, "         ........  ........\n");
       }
     } else {
       size_t words = frame->stack_size / sizeof(word_t);
@@ -324,37 +328,33 @@
       } else if (words > STACK_WORDS) {
         words = STACK_WORDS;
       }
-      dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
+      dump_stack_segment(backtrace, log, &sp, words, i);
     }
   }
 }
 
-static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
   if (backtrace->NumFrames()) {
-    _LOG(log, scope_flags, "\nbacktrace:\n");
-    dump_backtrace_to_log(backtrace, log, scope_flags, "    ");
+    _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
+    dump_backtrace_to_log(backtrace, log, "    ");
 
-    _LOG(log, scope_flags, "\nstack:\n");
-    dump_stack(backtrace, log, scope_flags);
+    _LOG(log, logtype::STACK, "\nstack:\n");
+    dump_stack(backtrace, log);
   }
 }
 
-static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
-  if (map != NULL) {
-    _LOG(log, scope_flags, "    %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
+static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) {
+  _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c %s\n",
+         (fault_addr? "--->" : "    "), map->start, map->end,
          (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
          (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
-  } else {
-    _LOG(log, scope_flags, "    (no %s)\n", what);
-  }
 }
 
-static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) {
-  scope_flags |= SCOPE_SENSITIVE;
+static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) {
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-    _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
+    _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
     return;
   }
   if (!signal_has_si_addr(si.si_signo)) {
@@ -367,55 +367,44 @@
     return;
   }
 
-  _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n",
-       reinterpret_cast<uintptr_t>(si.si_addr));
+  _LOG(log, logtype::MAPS, "\nmemory map: (fault address prefixed with --->)\n");
 
-  // Search for a match, or for a hole where the match would be.  The list
-  // is backward from the file content, so it starts at high addresses.
-  const backtrace_map_t* cur_map = NULL;
-  const backtrace_map_t* next_map = NULL;
-  const backtrace_map_t* prev_map = NULL;
+  bool found_map = false;
   for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    if (addr >= it->start && addr < it->end) {
-      cur_map = &*it;
-      if (it != map->begin()) {
-        prev_map = &*(it-1);
-      }
-      if (++it != map->end()) {
-        next_map = &*it;
-      }
-      break;
+    bool in_map = addr >= (*it).start && addr < (*it).end;
+    dump_map(log, &*it, in_map);
+    if(in_map) {
+      found_map = true;
     }
   }
-
-  // Show the map address in ascending order (like /proc/pid/maps).
-  dump_map(log, prev_map, "map below", scope_flags);
-  dump_map(log, cur_map, "map for address", scope_flags);
-  dump_map(log, next_map, "map above", scope_flags);
+  if(!found_map) {
+    _LOG(log, logtype::ERROR, "\nFault address was not in any map!");
+  }
 }
 
 static void dump_thread(
-    Backtrace* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) {
+    Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) {
+
   wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
 
-  dump_registers(log, backtrace->Tid(), scope_flags);
-  dump_backtrace_and_stack(backtrace, log, scope_flags);
-  if (IS_AT_FAULT(scope_flags)) {
-    dump_memory_and_code(log, backtrace->Tid(), scope_flags);
-    dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
-  }
+  dump_registers(log, backtrace->Tid());
+  dump_backtrace_and_stack(backtrace, log);
+
+  dump_memory_and_code(log, backtrace->Tid());
+  dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid());
 }
 
 // Return true if some thread is not detached cleanly
 static bool dump_sibling_thread_report(
     log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
   char task_path[64];
+
   snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
 
   DIR* d = opendir(task_path);
   // Bail early if the task directory cannot be opened
   if (d == NULL) {
-    XLOG("Cannot open /proc/%d/task\n", pid);
+    ALOGE("Cannot open /proc/%d/task\n", pid);
     return false;
   }
 
@@ -436,19 +425,23 @@
 
     // Skip this thread if cannot ptrace it
     if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
+      _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
       continue;
     }
 
-    _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
-    dump_thread_info(log, pid, new_tid, 0);
+    log->current_tid = new_tid;
+    _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+    dump_thread_info(log, pid, new_tid);
 
     UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
     if (backtrace->Unwind(0)) {
-      dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
+      dump_thread(backtrace.get(), log, total_sleep_time_usec);
     }
 
+    log->current_tid = log->crashed_tid;
+
     if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
-      LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
+      _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
       detach_failed = true;
     }
   }
@@ -472,7 +465,7 @@
     android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
 
   if (!logger_list) {
-    XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+    ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
     return;
   }
 
@@ -489,17 +482,17 @@
         // non-blocking EOF; we're done
         break;
       } else {
-        _LOG(log, 0, "Error while reading log: %s\n",
+        _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
           strerror(-actual));
         break;
       }
     } else if (actual == 0) {
-      _LOG(log, 0, "Got zero bytes while reading log: %s\n",
+      _LOG(log, logtype::ERROR, "Got zero bytes while reading log: %s\n",
         strerror(errno));
       break;
     }
 
-    // NOTE: if you XLOG something here, this will spin forever,
+    // NOTE: if you ALOGV something here, this will spin forever,
     // because you will be writing as fast as you're reading.  Any
     // high-frequency debug diagnostics should just be written to
     // the tombstone file.
@@ -511,7 +504,7 @@
     }
 
     if (first) {
-      _LOG(log, 0, "--------- %slog %s\n",
+      _LOG(log, logtype::HEADER, "--------- %slog %s\n",
         tail ? "tail end of " : "", filename);
       first = false;
     }
@@ -541,7 +534,7 @@
       AndroidLogEntry e;
       char buf[512];
       android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
-      _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
          'I', e.tag, e.message);
       continue;
@@ -568,7 +561,7 @@
         ++nl;
       }
 
-      _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
          prioChar, tag, msg);
 
@@ -608,7 +601,7 @@
   }
   msg[sizeof(msg) - 1] = '\0';
 
-  _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+  _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
 }
 
 // Dumps all information about the specified pid to the tombstone.
@@ -630,11 +623,11 @@
     TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
   }
 
-  _LOG(log, SCOPE_AT_FAULT,
+  _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
-  dump_build_info(log);
-  dump_revision_info(log);
-  dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
+  dump_header_info(log);
+  dump_thread_info(log, pid, tid);
+
   if (signal) {
     dump_signal_info(log, tid, signal, si_code);
   }
@@ -643,7 +636,7 @@
   UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
   if (backtrace->Unwind(0)) {
     dump_abort_message(backtrace.get(), log, abort_msg_address);
-    dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
+    dump_thread(backtrace.get(), log, total_sleep_time_usec);
   }
 
   if (want_logs) {
@@ -705,7 +698,7 @@
   }
 
   if (oldest < 0) {
-    LOG("Failed to find a valid tombstone, default to using tombstone 0.\n");
+    ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n");
     oldest = 0;
   }
 
@@ -713,7 +706,7 @@
   snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
   *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
   if (*fd < 0) {
-    LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
+    ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
     return NULL;
   }
   fchown(*fd, AID_SYSTEM, AID_SYSTEM);
@@ -751,14 +744,19 @@
 }
 
 char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
-                        uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet,
+                        uintptr_t abort_msg_address, bool dump_sibling_threads,
                         bool* detach_failed, int* total_sleep_time_usec) {
+
+  log_t log;
+  log.current_tid = tid;
+  log.crashed_tid = tid;
+
   if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
-    LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+    _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
   }
 
   if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
-    LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+    _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
   }
 
   int fd = -1;
@@ -766,25 +764,25 @@
   if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
     path = find_and_open_tombstone(&fd);
   } else {
-    LOG("Failed to restore security context, not writing tombstone.\n");
+    _LOG(&log, logtype::ERROR, "Failed to restore security context, not writing tombstone.\n");
   }
 
-  if (fd < 0 && quiet) {
-    LOG("Skipping tombstone write, nothing to do.\n");
+  if (fd < 0) {
+    _LOG(&log, logtype::ERROR, "Skipping tombstone write, nothing to do.\n");
     *detach_failed = false;
     return NULL;
   }
 
-  log_t log;
   log.tfd = fd;
   // Preserve amfd since it can be modified through the calls below without
   // being closed.
   int amfd = activity_manager_connect();
   log.amfd = amfd;
-  log.quiet = quiet;
   *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
                               dump_sibling_threads, total_sleep_time_usec);
 
+  ALOGI("\nTombstone written to: %s\n", path);
+
   // Either of these file descriptors can be -1, any error is ignored.
   close(amfd);
   close(fd);
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 3574e84..7e2b2fe 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -25,7 +25,7 @@
  * Returns the path of the tombstone, which must be freed using free(). */
 char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
                         uintptr_t abort_msg_address,
-                        bool dump_sibling_threads, bool quiet,
-                        bool* detach_failed, int* total_sleep_time_usec);
+                        bool dump_sibling_threads, bool* detach_failed,
+                        int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index d4c252f..a163344 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include "utility.h"
 
 #include <errno.h>
@@ -25,7 +27,6 @@
 
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
-#include <log/logd.h>
 
 const int sleep_time_usec = 50000;         // 0.05 seconds
 const int max_total_sleep_usec = 10000000; // 10 seconds
@@ -36,7 +37,7 @@
     int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
     if (written < 0) {
       // hard failure
-      LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
+      ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
       return -1;
     }
     to_write -= written;
@@ -44,10 +45,22 @@
   return len;
 }
 
-void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
-  bool want_tfd_write = log && log->tfd >= 0;
-  bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
-  bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
+// Whitelist output desired in the logcat output.
+bool is_allowed_in_logcat(enum logtype ltype) {
+  if ((ltype == ERROR)
+   || (ltype == HEADER)
+   || (ltype == REGISTERS)
+   || (ltype == BACKTRACE)) {
+    return true;
+  }
+  return false;
+}
+
+void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
+  bool write_to_tombstone = (log->tfd != -1);
+  bool write_to_logcat = is_allowed_in_logcat(ltype)
+                      && (log->crashed_tid == log->current_tid);
+  bool write_to_activitymanager = (log->amfd != -1);
 
   char buf[512];
   va_list ap;
@@ -60,13 +73,13 @@
     return;
   }
 
-  if (want_tfd_write) {
+  if (write_to_tombstone) {
     TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
   }
 
-  if (want_log_write) {
-    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, "DEBUG", buf);
-    if (want_amfd_write) {
+  if (write_to_logcat) {
+    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+    if (write_to_activitymanager) {
       int written = write_to_am(log->amfd, buf, len);
       if (written <= 0) {
         // timeout or other failure on write; stop informing the activity manager
@@ -83,25 +96,25 @@
     if (n < 0) {
       if (errno == EAGAIN)
         continue;
-      LOG("waitpid failed: %s\n", strerror(errno));
+      ALOGE("waitpid failed: %s\n", strerror(errno));
       return -1;
     } else if (n > 0) {
-      XLOG("waitpid: n=%d status=%08x\n", n, status);
+      ALOGV("waitpid: n=%d status=%08x\n", n, status);
       if (WIFSTOPPED(status)) {
         return WSTOPSIG(status);
       } else {
-        LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
+        ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
         return -1;
       }
     }
 
     if (*total_sleep_time_usec > max_total_sleep_usec) {
-      LOG("timed out waiting for tid=%d to die\n", tid);
+      ALOGE("timed out waiting for tid=%d to die\n", tid);
       return -1;
     }
 
     // not ready yet
-    XLOG("not ready yet\n");
+    ALOGV("not ready yet\n");
     usleep(sleep_time_usec);
     *total_sleep_time_usec += sleep_time_usec;
   }
@@ -111,7 +124,7 @@
   siginfo_t si;
   while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
     if (*total_sleep_time_usec > max_total_sleep_usec) {
-      LOG("timed out waiting for tid=%d to stop\n", tid);
+      ALOGE("timed out waiting for tid=%d to stop\n", tid);
       break;
     }
 
@@ -126,7 +139,7 @@
 #define DUMP_MEMORY_AS_ASCII 0
 #endif
 
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
     char code_buffer[64];
     char ascii_buffer[32];
     uintptr_t p, end;
@@ -190,6 +203,6 @@
             p += sizeof(long);
         }
         *asc_out = '\0';
-        _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, logtype::MEMORY, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 0f88605..ee4f035 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -26,43 +26,32 @@
     int tfd;
     /* Activity Manager socket file descriptor */
     int amfd;
-    /* if true, does not log anything to the Android logcat or Activity Manager */
-    bool quiet;
+    // The tid of the thread that crashed.
+    pid_t crashed_tid;
+    // The tid of the thread we are currently working with.
+    pid_t current_tid;
 } log_t;
 
-/* Log information onto the tombstone.  scopeFlags is a bitmask of the flags defined
- * here. */
-void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
+// List of types of logs to simplify the logging decision in _LOG
+enum logtype {
+  ERROR,
+  HEADER,
+  THREAD,
+  REGISTERS,
+  BACKTRACE,
+  MAPS,
+  MEMORY,
+  STACK,
+  LOGS
+};
+
+/* Log information onto the tombstone. */
+void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-/* The message pertains specifically to the faulting thread / process */
-#define SCOPE_AT_FAULT (1 << 0)
-/* The message contains sensitive information such as RAM contents */
-#define SCOPE_SENSITIVE  (1 << 1)
-
-#define IS_AT_FAULT(x)    (((x) & SCOPE_AT_FAULT) != 0)
-#define IS_SENSITIVE(x)    (((x) & SCOPE_SENSITIVE) != 0)
-
-/* Further helpful macros */
-#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-
-/* Set to 1 for normal debug traces */
-#if 0
-#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG(fmt...) do {} while(0)
-#endif
-
-/* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */
-#if 0
-#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG2(fmt...) do {} while(0)
-#endif
-
 int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
 void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
 
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags);
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
 
 #endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 141f19a..57330c1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -25,21 +25,21 @@
 #include "../utility.h"
 #include "../machine.h"
 
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
   struct pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-    _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
-  _LOG(log, scope_flags, "    eax %08lx  ebx %08lx  ecx %08lx  edx %08lx\n",
+  _LOG(log, logtype::REGISTERS, "    eax %08lx  ebx %08lx  ecx %08lx  edx %08lx\n",
        r.eax, r.ebx, r.ecx, r.edx);
-  _LOG(log, scope_flags, "    esi %08lx  edi %08lx\n",
+  _LOG(log, logtype::REGISTERS, "    esi %08lx  edi %08lx\n",
        r.esi, r.edi);
-  _LOG(log, scope_flags, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
+  _LOG(log, logtype::REGISTERS, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
        r.xcs, r.xds, r.xes, r.xfs, r.xss);
-  _LOG(log, scope_flags, "    eip %08lx  ebp %08lx  esp %08lx  flags %08lx\n",
+  _LOG(log, logtype::REGISTERS, "    eip %08lx  ebp %08lx  esp %08lx  flags %08lx\n",
        r.eip, r.ebp, r.esp, r.eflags);
 }
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index 406851a..af4f35a 100755
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -27,25 +27,25 @@
 #include "../utility.h"
 #include "../machine.h"
 
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
 }
 
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
     struct user_regs_struct r;
     if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-        _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
         return;
     }
-    _LOG(log, scope_flags, "    rax %016lx  rbx %016lx  rcx %016lx  rdx %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    rax %016lx  rbx %016lx  rcx %016lx  rdx %016lx\n",
          r.rax, r.rbx, r.rcx, r.rdx);
-    _LOG(log, scope_flags, "    rsi %016lx  rdi %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    rsi %016lx  rdi %016lx\n",
          r.rsi, r.rdi);
-    _LOG(log, scope_flags, "    r8  %016lx  r9  %016lx  r10 %016lx  r11 %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    r8  %016lx  r9  %016lx  r10 %016lx  r11 %016lx\n",
          r.r8, r.r9, r.r10, r.r11);
-    _LOG(log, scope_flags, "    r12 %016lx  r13 %016lx  r14 %016lx  r15 %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    r12 %016lx  r13 %016lx  r14 %016lx  r15 %016lx\n",
          r.r12, r.r13, r.r14, r.r15);
-    _LOG(log, scope_flags, "    cs  %016lx  ss  %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    cs  %016lx  ss  %016lx\n",
          r.cs, r.ss);
-    _LOG(log, scope_flags, "    rip %016lx  rbp %016lx  rsp %016lx  eflags %016lx\n",
+    _LOG(log, logtype::REGISTERS, "    rip %016lx  rbp %016lx  rsp %016lx  eflags %016lx\n",
          r.rip, r.rbp, r.rsp, r.eflags);
 }
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 9b84c3e..d30e771 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -126,7 +126,7 @@
         KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
 }
 
-#define UEVENT_MSG_LEN 1024
+#define UEVENT_MSG_LEN 2048
 static void uevent_event(void) {
     char msg[UEVENT_MSG_LEN+2];
     char *cp;
diff --git a/include/android/log.h b/include/android/log.h
index f5b1900..1c171b7 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -98,8 +98,16 @@
  */
 int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
 #if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
     __attribute__ ((format(printf, 3, 4)))
 #endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
     ;
 
 /*
@@ -117,8 +125,16 @@
                           const char *fmt, ...)
 #if defined(__GNUC__)
     __attribute__ ((noreturn))
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 4)))
+#else
     __attribute__ ((format(printf, 3, 4)))
 #endif
+#else
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
     ;
 
 #ifdef __cplusplus
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 2c70165..798db8b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -20,6 +20,7 @@
 #include <sys/cdefs.h>
 #include <stddef.h>
 #include <sys/system_properties.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -44,6 +45,64 @@
 */
 int property_get(const char *key, char *value, const char *default_value);
 
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+**   "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+**   "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+**   -- 0 prefix is octal
+**   -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
 /* property_set: returns 0 on success, < 0 on failure
 */
 int property_set(const char *key, const char *value);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index f5289c1..d8e938e 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -94,6 +94,7 @@
 #define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
 #define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
 
+#define AID_EVERYBODY     9997  /* shared between all apps in the same profile */
 #define AID_MISC          9998  /* access to misc storage */
 #define AID_NOBODY        9999
 
@@ -169,6 +170,7 @@
     { "net_bw_acct",   AID_NET_BW_ACCT, },
     { "net_bt_stack",  AID_NET_BT_STACK, },
 
+    { "everybody",     AID_EVERYBODY, },
     { "misc",          AID_MISC, },
     { "nobody",        AID_NOBODY, },
 };
@@ -242,7 +244,7 @@
 
     /* the following five files are INTENTIONALLY set-uid, but they
      * are NOT included on user builds. */
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/su" },
+    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
diff --git a/init/Android.mk b/init/Android.mk
index 15a23be..489dc93 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -25,7 +25,7 @@
 endif
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1
+LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
 endif
 
 # Enable ueventd logging
diff --git a/init/devices.c b/init/devices.c
index 3119e8e..ea9a4b2 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -15,6 +15,7 @@
  */
 
 #include <errno.h>
+#include <fnmatch.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -77,6 +78,7 @@
     unsigned int uid;
     unsigned int gid;
     unsigned short prefix;
+    unsigned short wildcard;
 };
 
 struct perm_node {
@@ -97,7 +99,8 @@
 
 int add_dev_perms(const char *name, const char *attr,
                   mode_t perm, unsigned int uid, unsigned int gid,
-                  unsigned short prefix) {
+                  unsigned short prefix,
+                  unsigned short wildcard) {
     struct perm_node *node = calloc(1, sizeof(*node));
     if (!node)
         return -ENOMEM;
@@ -116,6 +119,7 @@
     node->dp.uid = uid;
     node->dp.gid = gid;
     node->dp.prefix = prefix;
+    node->dp.wildcard = wildcard;
 
     if (attr)
         list_add_tail(&sys_perms, &node->plist);
@@ -140,6 +144,9 @@
         if (dp->prefix) {
             if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
                 continue;
+        } else if (dp->wildcard) {
+            if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
+                continue;
         } else {
             if (strcmp(upath, dp->name + 4))
                 continue;
@@ -180,6 +187,9 @@
         if (dp->prefix) {
             if (strncmp(path, dp->name, strlen(dp->name)))
                 continue;
+        } else if (dp->wildcard) {
+            if (fnmatch(dp->name, path, FNM_PATHNAME) != 0)
+                continue;
         } else {
             if (strcmp(path, dp->name))
                 continue;
@@ -196,7 +206,8 @@
 
 static void make_device(const char *path,
                         const char *upath UNUSED,
-                        int block, int major, int minor)
+                        int block, int major, int minor,
+                        const char **links)
 {
     unsigned uid;
     unsigned gid;
@@ -207,7 +218,7 @@
     mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
     if (sehandle) {
-        selabel_lookup(sehandle, &secontext, path, mode);
+        selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
         setfscreatecon(secontext);
     }
 
@@ -523,7 +534,7 @@
     int i;
 
     if(!strcmp(action, "add")) {
-        make_device(devpath, path, block, major, minor);
+        make_device(devpath, path, block, major, minor, (const char **)links);
         if (links) {
             for (i = 0; links[i]; i++)
                 make_link(devpath, links[i]);
diff --git a/init/devices.h b/init/devices.h
index a84fa58..5d0fe88 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -23,6 +23,7 @@
 extern void device_init(void);
 extern int add_dev_perms(const char *name, const char *attr,
                          mode_t perm, unsigned int uid,
-                         unsigned int gid, unsigned short prefix);
+                         unsigned int gid, unsigned short prefix,
+                         unsigned short wildcard);
 int get_device_fd();
 #endif	/* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 7ba25dc..c79929b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -868,6 +868,7 @@
 
 static bool selinux_is_disabled(void)
 {
+#ifdef ALLOW_DISABLE_SELINUX
     char tmp[PROP_VALUE_MAX];
 
     if (access("/sys/fs/selinux", F_OK) != 0) {
@@ -881,12 +882,14 @@
         /* SELinux is compiled into the kernel, but we've been told to disable it. */
         return true;
     }
+#endif
 
     return false;
 }
 
 static bool selinux_is_enforcing(void)
 {
+#ifdef ALLOW_DISABLE_SELINUX
     char tmp[PROP_VALUE_MAX];
 
     if (property_get("ro.boot.selinux", tmp) == 0) {
@@ -903,6 +906,7 @@
         ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
     }
 
+#endif
     return true;
 }
 
diff --git a/init/ueventd.c b/init/ueventd.c
index 662196d..4ad0cb9 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -122,6 +122,7 @@
     uid_t uid;
     gid_t gid;
     int prefix = 0;
+    int wildcard = 0;
     char *endptr;
     int ret;
     char *tmp = 0;
@@ -154,9 +155,13 @@
         name = tmp;
     } else {
         int len = strlen(name);
-        if (name[len - 1] == '*') {
+        char *wildcard_chr = strchr(name, '*');
+        if ((name[len - 1] == '*') &&
+            (wildcard_chr == (name + len - 1))) {
             prefix = 1;
             name[len - 1] = '\0';
+        } else if (wildcard_chr) {
+            wildcard = 1;
         }
     }
 
@@ -183,6 +188,6 @@
     }
     gid = ret;
 
-    add_dev_perms(name, attr, perm, uid, gid, prefix);
+    add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
     free(tmp);
 }
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
index 9882e31..2f55645 100644
--- a/libbacktrace/Android.build.mk
+++ b/libbacktrace/Android.build.mk
@@ -18,6 +18,7 @@
 
 LOCAL_MODULE := $(module)
 LOCAL_MODULE_TAGS := $(module_tag)
+LOCAL_MULTILIB := $($(module)_multilib)
 
 LOCAL_ADDITIONAL_DEPENDENCIES := \
     $(LOCAL_PATH)/Android.mk \
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 5a0bc7f..1de81e7 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -113,7 +113,9 @@
 build_target := SHARED_LIBRARY
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
+libbacktrace_libc++_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
+libbacktrace_libc++_multilib :=
 endif
 
 #-------------------------------------------------------------------------
@@ -186,4 +188,21 @@
 
 include $(BUILD_HOST_SHARED_LIBRARY)
 
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_libc++
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	BacktraceMap.cpp \
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # TARGET_BUILD_APPS
+
 endif # HOST_OS-darwin
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index e1d6f49..c0faed4 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -40,9 +40,6 @@
 	iosched_policy.c \
 	str_parms.c \
 
-commonHostSources := \
-        ashmem-host.c
-
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
@@ -61,13 +58,16 @@
     commonSources += \
         fs.c \
         multiuser.c \
-	socket_inaddr_any_server.c \
-	socket_local_client.c \
-	socket_local_server.c \
-	socket_loopback_client.c \
-	socket_loopback_server.c \
-	socket_network_client.c \
-	sockets.c \
+        socket_inaddr_any_server.c \
+        socket_local_client.c \
+        socket_local_server.c \
+        socket_loopback_client.c \
+        socket_loopback_server.c \
+        socket_network_client.c \
+        sockets.c \
+
+    commonHostSources += \
+        ashmem-host.c
 
 endif
 
@@ -81,6 +81,8 @@
 ifneq ($(HOST_OS),windows)
 LOCAL_CFLAGS += -Werror
 endif
+LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -94,6 +96,7 @@
 ifneq ($(HOST_OS),windows)
 LOCAL_CFLAGS += -Werror
 endif
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 # Tests for host
@@ -107,6 +110,7 @@
 LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_EXECUTABLE)
 
 
@@ -120,30 +124,36 @@
         ashmem-dev.c \
         debugger.c \
         klog.c \
+        memory.c \
         partition_utils.c \
         properties.c \
         qtaguid.c \
         trace.c \
-        uevent.c
+        uevent.c \
 
-ifeq ($(TARGET_ARCH),arm)
-    LOCAL_SRC_FILES += arch-arm/memset32.S
-else  # !arm
-    ifeq ($(TARGET_ARCH),x86)
-        LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-        LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
-    else # !x86
-        ifeq ($(TARGET_ARCH),mips)
-            LOCAL_SRC_FILES += arch-mips/android_memset.c
-        else # !mips
-            LOCAL_SRC_FILES += memory.c
-        endif # !mips
-    endif # !x86
-endif # !arm
+LOCAL_SRC_FILES_arm += \
+        arch-arm/memset32.S \
+
+LOCAL_SRC_FILES_mips += \
+        arch-mips/android_memset.c \
+
+LOCAL_SRC_FILES_x86 += \
+        arch-x86/android_memset16.S \
+        arch-x86/android_memset32.S \
+
+LOCAL_SRC_FILES_x86_64 += \
+        arch-x86_64/android_memset16_SSE2-atom.S \
+        arch-x86_64/android_memset32_SSE2-atom.S \
+
+LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(targetSmpFlag) -Werror
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -154,6 +164,7 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_CFLAGS += $(targetSmpFlag) -Werror
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -162,6 +173,7 @@
 LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
new file mode 100644
index 0000000..48a10ed
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#include "cache.h"
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n)	.p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define JMPTBL(I, B)	I - B
+
+/* Branch to an entry in a jump table.  TABLE is a jump table with
+   relative offsets.  INDEX is a register contains the index into the
+   jump table.  SCALE is the scale of INDEX.  */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+	lea    TABLE(%rip), %r11;						\
+	movslq (%r11, INDEX, SCALE), INDEX;				\
+	lea    (%r11, INDEX), INDEX;					\
+	jmp    *INDEX
+
+	.section .text.sse2,"ax",@progbits
+	ALIGN (4)
+ENTRY (android_memset16)	// Address in rdi
+	shr    $1, %rdx			// Count in rdx
+	movzwl %si, %ecx
+	/* Fill the whole ECX with pattern.  */
+	shl    $16, %esi
+	or     %esi, %ecx		// Pattern in ecx
+
+	cmp    $32, %rdx
+	jae    L(32wordsormore)
+
+L(write_less32words):
+	lea    (%rdi, %rdx, 2), %rdi
+	BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_less32words):
+	.int	JMPTBL (L(write_0words), L(table_less32words))
+	.int	JMPTBL (L(write_1words), L(table_less32words))
+	.int	JMPTBL (L(write_2words), L(table_less32words))
+	.int	JMPTBL (L(write_3words), L(table_less32words))
+	.int	JMPTBL (L(write_4words), L(table_less32words))
+	.int	JMPTBL (L(write_5words), L(table_less32words))
+	.int	JMPTBL (L(write_6words), L(table_less32words))
+	.int	JMPTBL (L(write_7words), L(table_less32words))
+	.int	JMPTBL (L(write_8words), L(table_less32words))
+	.int	JMPTBL (L(write_9words), L(table_less32words))
+	.int	JMPTBL (L(write_10words), L(table_less32words))
+	.int	JMPTBL (L(write_11words), L(table_less32words))
+	.int	JMPTBL (L(write_12words), L(table_less32words))
+	.int	JMPTBL (L(write_13words), L(table_less32words))
+	.int	JMPTBL (L(write_14words), L(table_less32words))
+	.int	JMPTBL (L(write_15words), L(table_less32words))
+	.int	JMPTBL (L(write_16words), L(table_less32words))
+	.int	JMPTBL (L(write_17words), L(table_less32words))
+	.int	JMPTBL (L(write_18words), L(table_less32words))
+	.int	JMPTBL (L(write_19words), L(table_less32words))
+	.int	JMPTBL (L(write_20words), L(table_less32words))
+	.int	JMPTBL (L(write_21words), L(table_less32words))
+	.int	JMPTBL (L(write_22words), L(table_less32words))
+	.int	JMPTBL (L(write_23words), L(table_less32words))
+	.int	JMPTBL (L(write_24words), L(table_less32words))
+	.int	JMPTBL (L(write_25words), L(table_less32words))
+	.int	JMPTBL (L(write_26words), L(table_less32words))
+	.int	JMPTBL (L(write_27words), L(table_less32words))
+	.int	JMPTBL (L(write_28words), L(table_less32words))
+	.int	JMPTBL (L(write_29words), L(table_less32words))
+	.int	JMPTBL (L(write_30words), L(table_less32words))
+	.int	JMPTBL (L(write_31words), L(table_less32words))
+	.popsection
+
+	ALIGN (4)
+L(write_28words):
+	movl   %ecx, -56(%rdi)
+	movl   %ecx, -52(%rdi)
+L(write_24words):
+	movl   %ecx, -48(%rdi)
+	movl   %ecx, -44(%rdi)
+L(write_20words):
+	movl   %ecx, -40(%rdi)
+	movl   %ecx, -36(%rdi)
+L(write_16words):
+	movl   %ecx, -32(%rdi)
+	movl   %ecx, -28(%rdi)
+L(write_12words):
+	movl   %ecx, -24(%rdi)
+	movl   %ecx, -20(%rdi)
+L(write_8words):
+	movl   %ecx, -16(%rdi)
+	movl   %ecx, -12(%rdi)
+L(write_4words):
+	movl   %ecx, -8(%rdi)
+	movl   %ecx, -4(%rdi)
+L(write_0words):
+	ret
+
+	ALIGN (4)
+L(write_29words):
+	movl   %ecx, -58(%rdi)
+	movl   %ecx, -54(%rdi)
+L(write_25words):
+	movl   %ecx, -50(%rdi)
+	movl   %ecx, -46(%rdi)
+L(write_21words):
+	movl   %ecx, -42(%rdi)
+	movl   %ecx, -38(%rdi)
+L(write_17words):
+	movl   %ecx, -34(%rdi)
+	movl   %ecx, -30(%rdi)
+L(write_13words):
+	movl   %ecx, -26(%rdi)
+	movl   %ecx, -22(%rdi)
+L(write_9words):
+	movl   %ecx, -18(%rdi)
+	movl   %ecx, -14(%rdi)
+L(write_5words):
+	movl   %ecx, -10(%rdi)
+	movl   %ecx, -6(%rdi)
+L(write_1words):
+	mov	%cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(write_30words):
+	movl   %ecx, -60(%rdi)
+	movl   %ecx, -56(%rdi)
+L(write_26words):
+	movl   %ecx, -52(%rdi)
+	movl   %ecx, -48(%rdi)
+L(write_22words):
+	movl   %ecx, -44(%rdi)
+	movl   %ecx, -40(%rdi)
+L(write_18words):
+	movl   %ecx, -36(%rdi)
+	movl   %ecx, -32(%rdi)
+L(write_14words):
+	movl   %ecx, -28(%rdi)
+	movl   %ecx, -24(%rdi)
+L(write_10words):
+	movl   %ecx, -20(%rdi)
+	movl   %ecx, -16(%rdi)
+L(write_6words):
+	movl   %ecx, -12(%rdi)
+	movl   %ecx, -8(%rdi)
+L(write_2words):
+	movl   %ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(write_31words):
+	movl   %ecx, -62(%rdi)
+	movl   %ecx, -58(%rdi)
+L(write_27words):
+	movl   %ecx, -54(%rdi)
+	movl   %ecx, -50(%rdi)
+L(write_23words):
+	movl   %ecx, -46(%rdi)
+	movl   %ecx, -42(%rdi)
+L(write_19words):
+	movl   %ecx, -38(%rdi)
+	movl   %ecx, -34(%rdi)
+L(write_15words):
+	movl   %ecx, -30(%rdi)
+	movl   %ecx, -26(%rdi)
+L(write_11words):
+	movl   %ecx, -22(%rdi)
+	movl   %ecx, -18(%rdi)
+L(write_7words):
+	movl   %ecx, -14(%rdi)
+	movl   %ecx, -10(%rdi)
+L(write_3words):
+	movl   %ecx, -6(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(32wordsormore):
+	shl    $1, %rdx
+	test   $0x01, %edi
+	jz     L(aligned2bytes)
+	mov    %ecx, (%rdi)
+	mov    %ecx, -4(%rdi, %rdx)
+	sub    $2, %rdx
+	add    $1, %rdi
+	rol    $8, %ecx
+L(aligned2bytes):
+	/* Fill xmm0 with the pattern.  */
+	movd   %ecx, %xmm0
+	pshufd $0, %xmm0, %xmm0
+
+	testl  $0xf, %edi
+	jz     L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned.  */
+	movdqu %xmm0, (%rdi)
+	mov    %rdi, %rsi
+	and    $-16, %rdi
+	add    $16, %rdi
+	sub    %rdi, %rsi
+	add    %rsi, %rdx
+
+	ALIGN (4)
+L(aligned_16):
+	cmp    $128, %rdx
+	jge    L(128bytesormore)
+
+L(aligned_16_less128bytes):
+	add    %rdx, %rdi
+	shr    $1, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore):
+	cmp    $SHARED_CACHE_SIZE, %rdx
+	jg     L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_normal)
+
+L(128bytesless_normal):
+	add    %rdx, %rdi
+	shr    $1, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore_nt):
+	sub    $128, %rdx
+	movntdq %xmm0, (%rdi)
+	movntdq %xmm0, 0x10(%rdi)
+	movntdq %xmm0, 0x20(%rdi)
+	movntdq %xmm0, 0x30(%rdi)
+	movntdq %xmm0, 0x40(%rdi)
+	movntdq %xmm0, 0x50(%rdi)
+	movntdq %xmm0, 0x60(%rdi)
+	movntdq %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_nt)
+
+	sfence
+	add    %rdx, %rdi
+	shr    $1, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_16_128bytes):
+	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
+	.popsection
+
+	ALIGN (4)
+L(aligned_16_112bytes):
+	movdqa %xmm0, -112(%rdi)
+L(aligned_16_96bytes):
+	movdqa %xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+	movdqa %xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+	movdqa %xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+	movdqa %xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+	movdqa %xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+	movdqa %xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+	ret
+
+	ALIGN (4)
+L(aligned_16_114bytes):
+	movdqa %xmm0, -114(%rdi)
+L(aligned_16_98bytes):
+	movdqa %xmm0, -98(%rdi)
+L(aligned_16_82bytes):
+	movdqa %xmm0, -82(%rdi)
+L(aligned_16_66bytes):
+	movdqa %xmm0, -66(%rdi)
+L(aligned_16_50bytes):
+	movdqa %xmm0, -50(%rdi)
+L(aligned_16_34bytes):
+	movdqa %xmm0, -34(%rdi)
+L(aligned_16_18bytes):
+	movdqa %xmm0, -18(%rdi)
+L(aligned_16_2bytes):
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_116bytes):
+	movdqa %xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+	movdqa %xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+	movdqa %xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+	movdqa %xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+	movdqa %xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+	movdqa %xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+	movdqa %xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+	movl   %ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_118bytes):
+	movdqa %xmm0, -118(%rdi)
+L(aligned_16_102bytes):
+	movdqa %xmm0, -102(%rdi)
+L(aligned_16_86bytes):
+	movdqa %xmm0, -86(%rdi)
+L(aligned_16_70bytes):
+	movdqa %xmm0, -70(%rdi)
+L(aligned_16_54bytes):
+	movdqa %xmm0, -54(%rdi)
+L(aligned_16_38bytes):
+	movdqa %xmm0, -38(%rdi)
+L(aligned_16_22bytes):
+	movdqa %xmm0, -22(%rdi)
+L(aligned_16_6bytes):
+	movl   %ecx, -6(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_120bytes):
+	movdqa %xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+	movdqa %xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+	movdqa %xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+	movdqa %xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+	movdqa %xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+	movdqa %xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+	movdqa %xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+	movq   %xmm0, -8(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_122bytes):
+	movdqa %xmm0, -122(%rdi)
+L(aligned_16_106bytes):
+	movdqa %xmm0, -106(%rdi)
+L(aligned_16_90bytes):
+	movdqa %xmm0, -90(%rdi)
+L(aligned_16_74bytes):
+	movdqa %xmm0, -74(%rdi)
+L(aligned_16_58bytes):
+	movdqa %xmm0, -58(%rdi)
+L(aligned_16_42bytes):
+	movdqa %xmm0, -42(%rdi)
+L(aligned_16_26bytes):
+	movdqa %xmm0, -26(%rdi)
+L(aligned_16_10bytes):
+	movq   %xmm0, -10(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_124bytes):
+	movdqa %xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+	movdqa %xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+	movdqa %xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+	movdqa %xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+	movdqa %xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+	movdqa %xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+	movdqa %xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+	movq   %xmm0, -12(%rdi)
+	movl   %ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_126bytes):
+	movdqa %xmm0, -126(%rdi)
+L(aligned_16_110bytes):
+	movdqa %xmm0, -110(%rdi)
+L(aligned_16_94bytes):
+	movdqa %xmm0, -94(%rdi)
+L(aligned_16_78bytes):
+	movdqa %xmm0, -78(%rdi)
+L(aligned_16_62bytes):
+	movdqa %xmm0, -62(%rdi)
+L(aligned_16_46bytes):
+	movdqa %xmm0, -46(%rdi)
+L(aligned_16_30bytes):
+	movdqa %xmm0, -30(%rdi)
+L(aligned_16_14bytes):
+	movq   %xmm0, -14(%rdi)
+	movl   %ecx, -6(%rdi)
+	movw   %cx, -2(%rdi)
+	ret
+
+END (android_memset16)
diff --git a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
new file mode 100644
index 0000000..4bdea8e
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#include "cache.h"
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n)	.p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define JMPTBL(I, B)	I - B
+
+/* Branch to an entry in a jump table.  TABLE is a jump table with
+   relative offsets.  INDEX is a register contains the index into the
+   jump table.  SCALE is the scale of INDEX.  */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+	lea    TABLE(%rip), %r11;						\
+	movslq (%r11, INDEX, SCALE), INDEX;				\
+	lea    (%r11, INDEX), INDEX;					\
+	jmp    *INDEX
+
+	.section .text.sse2,"ax",@progbits
+	ALIGN (4)
+ENTRY (android_memset32)	// Address in rdi
+	shr    $2, %rdx			// Count in rdx
+	movl   %esi, %ecx		// Pattern in ecx
+
+	cmp    $16, %rdx
+	jae    L(16dbwordsormore)
+
+L(write_less16dbwords):
+	lea    (%rdi, %rdx, 4), %rdi
+	BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_less16dbwords):
+	.int	JMPTBL (L(write_0dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_1dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_2dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_3dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_4dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_5dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_6dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_7dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_8dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_9dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_10dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_11dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_12dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_13dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_14dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_15dbwords), L(table_less16dbwords))
+	.popsection
+
+	ALIGN (4)
+L(write_15dbwords):
+	movl   %ecx, -60(%rdi)
+L(write_14dbwords):
+	movl   %ecx, -56(%rdi)
+L(write_13dbwords):
+	movl   %ecx, -52(%rdi)
+L(write_12dbwords):
+	movl   %ecx, -48(%rdi)
+L(write_11dbwords):
+	movl   %ecx, -44(%rdi)
+L(write_10dbwords):
+	movl   %ecx, -40(%rdi)
+L(write_9dbwords):
+	movl   %ecx, -36(%rdi)
+L(write_8dbwords):
+	movl   %ecx, -32(%rdi)
+L(write_7dbwords):
+	movl   %ecx, -28(%rdi)
+L(write_6dbwords):
+	movl   %ecx, -24(%rdi)
+L(write_5dbwords):
+	movl   %ecx, -20(%rdi)
+L(write_4dbwords):
+	movl   %ecx, -16(%rdi)
+L(write_3dbwords):
+	movl   %ecx, -12(%rdi)
+L(write_2dbwords):
+	movl   %ecx, -8(%rdi)
+L(write_1dbwords):
+	movl   %ecx, -4(%rdi)
+L(write_0dbwords):
+	ret
+
+	ALIGN (4)
+L(16dbwordsormore):
+	test   $3, %edi
+	jz     L(aligned4bytes)
+	mov    %ecx, (%rdi)
+	mov    %ecx, -4(%rdi, %rdx, 4)
+	sub    $1, %rdx
+	rol    $24, %ecx
+	add    $1, %rdi
+	test   $3, %edi
+	jz     L(aligned4bytes)
+	ror    $8, %ecx
+	add    $1, %rdi
+	test   $3, %edi
+	jz     L(aligned4bytes)
+	ror    $8, %ecx
+	add    $1, %rdi
+L(aligned4bytes):
+	shl    $2, %rdx
+
+	/* Fill xmm0 with the pattern.  */
+	movd   %ecx, %xmm0
+	pshufd $0, %xmm0, %xmm0
+
+	testl  $0xf, %edi
+	jz     L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned.  */
+	movdqu %xmm0, (%rdi)
+	mov    %rdi, %rsi
+	and    $-16, %rdi
+	add    $16, %rdi
+	sub    %rdi, %rsi
+	add    %rsi, %rdx
+
+	ALIGN (4)
+L(aligned_16):
+	cmp    $128, %rdx
+	jge    L(128bytesormore)
+
+L(aligned_16_less128bytes):
+	add    %rdx, %rdi
+	shr    $2, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore):
+	cmp    $SHARED_CACHE_SIZE, %rdx
+	jg     L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jl     L(128bytesless_normal)
+
+	sub    $128, %rdx
+	movdqa %xmm0, (%rdi)
+	movdqa %xmm0, 0x10(%rdi)
+	movdqa %xmm0, 0x20(%rdi)
+	movdqa %xmm0, 0x30(%rdi)
+	movdqa %xmm0, 0x40(%rdi)
+	movdqa %xmm0, 0x50(%rdi)
+	movdqa %xmm0, 0x60(%rdi)
+	movdqa %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_normal)
+
+L(128bytesless_normal):
+	add    %rdx, %rdi
+	shr    $2, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	ALIGN (4)
+L(128bytesormore_nt):
+	sub    $128, %rdx
+	movntdq %xmm0, (%rdi)
+	movntdq %xmm0, 0x10(%rdi)
+	movntdq %xmm0, 0x20(%rdi)
+	movntdq %xmm0, 0x30(%rdi)
+	movntdq %xmm0, 0x40(%rdi)
+	movntdq %xmm0, 0x50(%rdi)
+	movntdq %xmm0, 0x60(%rdi)
+	movntdq %xmm0, 0x70(%rdi)
+	lea    128(%rdi), %rdi
+	cmp    $128, %rdx
+	jge    L(128bytesormore_nt)
+
+	sfence
+	add    %rdx, %rdi
+	shr    $2, %rdx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_16_128bytes):
+	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+	.popsection
+
+	ALIGN (4)
+L(aligned_16_112bytes):
+	movdqa	%xmm0, -112(%rdi)
+L(aligned_16_96bytes):
+	movdqa	%xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+	movdqa	%xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+	movdqa	%xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+	movdqa	%xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+	movdqa	%xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+	movdqa	%xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+	ret
+
+	ALIGN (4)
+L(aligned_16_116bytes):
+	movdqa	%xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+	movdqa	%xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+	movdqa	%xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+	movdqa	%xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+	movdqa	%xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+	movdqa	%xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+	movdqa	%xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+	movl	%ecx, -4(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_120bytes):
+	movdqa	%xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+	movdqa	%xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+	movdqa	%xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+	movdqa	%xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+	movdqa	%xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+	movdqa	%xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+	movdqa	%xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+	movq	%xmm0, -8(%rdi)
+	ret
+
+	ALIGN (4)
+L(aligned_16_124bytes):
+	movdqa	%xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+	movdqa	%xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+	movdqa	%xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+	movdqa	%xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+	movdqa	%xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+	movdqa	%xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+	movdqa	%xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+	movq	%xmm0, -12(%rdi)
+	movl	%ecx, -4(%rdi)
+	ret
+
+END (android_memset32)
diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h
new file mode 100644
index 0000000..ab5dd2f
--- /dev/null
+++ b/libcutils/arch-x86_64/cache.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#if defined(__slm__)
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE	(1024*1024)			/* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE		(24*1024)			/* Silvermont L1 Data Cache */
+#else
+/* Values are optimized for Atom */
+#define SHARED_CACHE_SIZE	(512*1024)			/* Atom L2 Cache */
+#define DATA_CACHE_SIZE		(24*1024)			/* Atom L1 Data Cache */
+#endif
+
+#define SHARED_CACHE_SIZE_HALF	(SHARED_CACHE_SIZE / 2)
+#define DATA_CACHE_SIZE_HALF	(DATA_CACHE_SIZE / 2)
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index 7873964..4ac4f57 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -22,6 +22,8 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -36,83 +38,83 @@
 #define __unused __attribute__((__unused__))
 #endif
 
+static pthread_once_t seed_initialized = PTHREAD_ONCE_INIT;
+static void initialize_random() {
+    srand(time(NULL) + getpid());
+}
+
 int ashmem_create_region(const char *ignored __unused, size_t size)
 {
-	static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
-				  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-	char name[64];
-	unsigned int retries = 0;
-	pid_t pid = getpid();
-	int fd;
+    static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    char name[64];
+    unsigned int retries = 0;
+    pid_t pid = getpid();
+    int fd;
+    if (pthread_once(&seed_initialized, &initialize_random) != 0) {
+        return -1;
+    }
+    do {
+        /* not beautiful, its just wolf-like loop unrolling */
+        snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
+        pid,
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
 
-	srand(time(NULL) + pid);
-
-retry:
-	/* not beautiful, its just wolf-like loop unrolling */
-	snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
-		pid,
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-		txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
-
-	/* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
-	fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
-	if (fd == -1) {
-		/* unlikely, but if we failed because `name' exists, retry */
-		if (errno == EEXIST && ++retries < 6)
-			goto retry;
-		return -1;
-	}
-
-	/* truncate the file to `len' bytes */
-	if (ftruncate(fd, size) == -1)
-		goto error;
-
-	if (unlink(name) == -1)
-		goto error;
-
-	return fd;
-error:
-	close(fd);
-	return -1;
+        /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
+        fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
+        if (fd == -1) {
+            /* unlikely, but if we failed because `name' exists, retry */
+            if (errno != EEXIST || ++retries >= 6) {
+                return -1;
+            }
+        }
+    } while (fd == -1);
+    /* truncate the file to `len' bytes */
+    if (ftruncate(fd, size) != -1 && unlink(name) != -1) {
+        return fd;
+    }
+    close(fd);
+    return -1;
 }
 
 int ashmem_set_prot_region(int fd __unused, int prot __unused)
 {
-	return 0;
+    return 0;
 }
 
 int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-	return ASHMEM_NOT_PURGED;
+    return ASHMEM_NOT_PURGED;
 }
 
 int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-	return ASHMEM_IS_UNPINNED;
+    return ASHMEM_IS_UNPINNED;
 }
 
 int ashmem_get_size_region(int fd)
 {
-        struct stat buf;
-        int result;
+    struct stat buf;
+    int result;
 
-        result = fstat(fd, &buf);
-        if (result == -1) {
-                return -1;
-        }
+    result = fstat(fd, &buf);
+    if (result == -1) {
+        return -1;
+    }
 
-        // Check if this is an "ashmem" region.
-        // TODO: This is very hacky, and can easily break. We need some reliable indicator.
-        if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
-                errno = ENOTTY;
-                return -1;
-        }
+    // Check if this is an "ashmem" region.
+    // TODO: This is very hacky, and can easily break. We need some reliable indicator.
+    if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
+        errno = ENOTTY;
+        return -1;
+    }
 
-        return (int)buf.st_size;  // TODO: care about overflow (> 2GB file)?
+    return (int)buf.st_size;    // TODO: care about overflow (> 2GB file)?
 }
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index 6dca911..2db473d 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "../../../bionic/libc/bionic/dlmalloc.h"
 #include "log/log.h"
 
 #define UNUSED __attribute__((__unused__))
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 67e101d..a6da9ca 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -21,31 +21,19 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifdef HAVE_SCHED_H
-
 #include <cutils/iosched_policy.h>
 
 #ifdef HAVE_ANDROID_OS
-/* #include <linux/ioprio.h> */
-extern int ioprio_set(int which, int who, int ioprio);
-extern int ioprio_get(int which, int who);
+#include <linux/ioprio.h>
+#include <sys/syscall.h>
 #define __android_unused
 #else
 #define __android_unused __attribute__((__unused__))
 #endif
 
-enum {
-    WHO_PROCESS = 1,
-    WHO_PGRP,
-    WHO_USER,
-};
-
-#define CLASS_SHIFT 13
-#define IOPRIO_NORM 4
-
 int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
 #ifdef HAVE_ANDROID_OS
-    if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
+    if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) {
         return -1;
     }
 #endif
@@ -56,11 +44,11 @@
 #ifdef HAVE_ANDROID_OS
     int rc;
 
-    if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
+    if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) {
         return -1;
     }
 
-    *clazz = (rc >> CLASS_SHIFT);
+    *clazz = (rc >> IOPRIO_CLASS_SHIFT);
     *ioprio = (rc & 0xff);
 #else
     *clazz = IoSchedClass_NONE;
@@ -68,5 +56,3 @@
 #endif
     return 0;
 }
-
-#endif /* HAVE_SCHED_H */
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 28d8b2f..b283658 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -15,17 +15,95 @@
  */
 
 #define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
 
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <unistd.h>
 #include <cutils/sockets.h>
 #include <errno.h>
 #include <assert.h>
 
 #include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
 #include "loghack.h"
 
+int8_t property_get_bool(const char *key, int8_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    int8_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+    int len = property_get(key, buf, "");
+    if (len == 1) {
+        char ch = buf[0];
+        if (ch == '0' || ch == 'n') {
+            result = false;
+        } else if (ch == '1' || ch == 'y') {
+            result = true;
+        }
+    } else if (len > 1) {
+         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+            result = false;
+        } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+        intmax_t default_value) {
+    if (!key) {
+        return default_value;
+    }
+
+    intmax_t result = default_value;
+    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char *end = NULL;
+
+    int len = property_get(key, buf, "");
+    if (len > 0) {
+        int tmp = errno;
+        errno = 0;
+
+        // Infer base automatically
+        result = strtoimax(buf, &end, /*base*/0);
+        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+            // Over or underflow
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+        } else if (result < lower_bound || result > upper_bound) {
+            // Out of range of requested bounds
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+        } else if (end == buf) {
+            // Numeric conversion failed
+            result = default_value;
+            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+                    __FUNCTION__, key, default_value);
+        }
+
+        errno = tmp;
+    }
+
+    return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
@@ -44,10 +122,13 @@
     if(len > 0) {
         return len;
     }
-    
     if(default_value) {
         len = strlen(default_value);
-        memcpy(value, default_value, len + 1);
+        if (len >= PROPERTY_VALUE_MAX) {
+            len = PROPERTY_VALUE_MAX - 1;
+        }
+        memcpy(value, default_value, len);
+        value[len] = '\0';
     }
     return len;
 }
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
new file mode 100644
index 0000000..d3e07f8
--- /dev/null
+++ b/libcutils/tests/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+test_src_files := \
+    PropertiesTest.cpp \
+
+shared_libraries := \
+    libutils \
+    liblog
+
+static_libraries := \
+    libcutils
+
+LOCAL_SHARED_LIBRARIES := $(shared_libraries)
+LOCAL_STATIC_LIBRARIES := $(static_libraries)
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_MODULE := libcutils_test
+include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
new file mode 100644
index 0000000..659821c
--- /dev/null
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Properties_test"
+#include <utils/Log.h>
+#include <gtest/gtest.h>
+
+#include <cutils/properties.h>
+#include <limits.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+namespace android {
+
+#define STRINGIFY_INNER(x) #x
+#define STRINGIFY(x) STRINGIFY_INNER(x)
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ASSERT_OK(x) ASSERT_EQ(0, (x))
+#define EXPECT_OK(x) EXPECT_EQ(0, (x))
+
+#define PROPERTY_TEST_KEY "libcutils.test.key"
+#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>"
+
+template <typename T>
+static std::string HexString(T value) {
+    std::stringstream ss;
+    ss << "0x" << std::hex << std::uppercase << value;
+    return ss.str();
+}
+
+template <typename T>
+static ::testing::AssertionResult AssertEqualHex(const char *mExpr,
+        const char *nExpr,
+        T m,
+        T n) {
+    if (m == n) {
+        return ::testing::AssertionSuccess();
+    }
+
+    return ::testing::AssertionFailure()
+        << mExpr << " and " << nExpr << " (expected: " << HexString(m) <<
+        ", actual: " << HexString(n) << ") are not equal";
+}
+
+class PropertiesTest : public testing::Test {
+public:
+    PropertiesTest() : mValue() {}
+protected:
+    virtual void SetUp() {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+    }
+
+    virtual void TearDown() {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+    }
+
+    char mValue[PROPERTY_VALUE_MAX];
+
+    template <typename T>
+    static std::string ToString(T value) {
+        std::stringstream ss;
+        ss << value;
+
+        return ss.str();
+    }
+
+    // Return length of property read; value is written into mValue
+    int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) {
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'";
+        return property_get(PROPERTY_TEST_KEY, mValue, defaultValue);
+    }
+
+    void ResetValue(unsigned char c = 0xFF) {
+        for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+            mValue[i] = (char) c;
+        }
+    }
+};
+
+TEST_F(PropertiesTest, SetString) {
+
+    // Null key -> unsuccessful set
+    {
+        // Null key -> fails
+        EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
+    }
+
+    // Null value -> returns default value
+    {
+        // Null value -> OK , and it clears the value
+        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+        ResetValue();
+
+        // Since the value is null, default value will be returned
+        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
+        EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
+    }
+
+    // Trivial case => get returns what was set
+    {
+        int len = SetAndGetProperty("hello_world");
+        EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
+        EXPECT_STREQ("hello_world", mValue);
+        ResetValue();
+    }
+
+    // Set to empty string => get returns default always
+    {
+        const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
+        int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+        EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
+        EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
+        ResetValue();
+    }
+
+    // Set to max length => get returns what was set
+    {
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+
+        int len = SetAndGetProperty(maxLengthString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+
+    // Set to max length + 1 => set fails
+    {
+        const char* VALID_TEST_VALUE = "VALID_VALUE";
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
+
+        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+        // Expect that the value set fails since it's too long
+        EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
+        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+
+        EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
+        EXPECT_STREQ(VALID_TEST_VALUE, mValue);
+        ResetValue();
+    }
+}
+
+TEST_F(PropertiesTest, GetString) {
+
+    // Try to use a default value that's too long => set fails
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+        // Expect that the value is truncated since it's too long (by 1)
+        int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+}
+
+TEST_F(PropertiesTest, GetBool) {
+    /**
+     * TRUE
+     */
+    const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+        EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
+    }
+
+    /**
+     * FALSE
+     */
+    const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+        EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
+    }
+
+    /**
+     * NEITHER
+     */
+    const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
+            "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
+            "+0", "-0", "00", "  00  ", "  false", "false  ",
+    };
+    for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
+
+        // The default value should always be used
+        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+        EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
+
+        val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+        EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
+    }
+}
+
+TEST_F(PropertiesTest, GetInt64) {
+    const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
+
+    const std::string longMaxString = ToString(INT64_MAX);
+    const std::string longStringOverflow = longMaxString + "0";
+
+    const std::string longMinString = ToString(INT64_MIN);
+    const std::string longStringUnderflow = longMinString + "0";
+
+    const char* setValues[] = {
+        // base 10
+        "1", "2", "12345", "-1", "-2", "-12345",
+        // base 16
+        "0xFF", "0x0FF", "0xC0FFEE",
+        // base 8
+        "0", "01234", "07",
+        // corner cases
+        "       2", "2      ", "+0", "-0", "  +0   ", longMaxString.c_str(), longMinString.c_str(),
+        // failing cases
+        NULL, "", " ", "    ", "hello", "     true     ", "y",
+        longStringOverflow.c_str(), longStringUnderflow.c_str(),
+    };
+
+    int64_t getValues[] = {
+        // base 10
+        1, 2, 12345, -1, -2, -12345,
+        // base 16
+        0xFF, 0x0FF, 0xC0FFEE,
+        // base 8
+        0, 01234, 07,
+        // corner cases
+        2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
+        // failing cases
+        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+        DEFAULT_VALUE, DEFAULT_VALUE,
+    };
+
+    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+        int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+    }
+}
+
+TEST_F(PropertiesTest, GetInt32) {
+    const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
+
+    const std::string intMaxString = ToString(INT32_MAX);
+    const std::string intStringOverflow = intMaxString + "0";
+
+    const std::string intMinString = ToString(INT32_MIN);
+    const std::string intStringUnderflow = intMinString + "0";
+
+    const char* setValues[] = {
+        // base 10
+        "1", "2", "12345", "-1", "-2", "-12345",
+        // base 16
+        "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
+        // base 8
+        "0", "01234", "07",
+        // corner cases
+        "       2", "2      ", "+0", "-0", "  +0   ", intMaxString.c_str(), intMinString.c_str(),
+        // failing cases
+        NULL, "", " ", "    ", "hello", "     true     ", "y",
+        intStringOverflow.c_str(), intStringUnderflow.c_str(),
+    };
+
+    int32_t getValues[] = {
+        // base 10
+        1, 2, 12345, -1, -2, -12345,
+        // base 16
+        0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
+        // base 8
+        0, 01234, 07,
+        // corner cases
+        2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
+        // failing cases
+        DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+        DEFAULT_VALUE, DEFAULT_VALUE,
+    };
+
+    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+        int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+        EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+    }
+}
+
+} // namespace android
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 69ca416..a7eead9 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -58,6 +58,7 @@
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_host_sources)
 LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -66,6 +67,7 @@
 ifeq ($(strip $(HOST_OS)),linux)
 LOCAL_LDLIBS := -lrt
 endif
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 0abc375..9839729 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -99,7 +99,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        (log_id_t)LOG_ID_MAIN, O_RDONLY | O_NDELAY, 1000, pid)));
+        (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
 
     char b[80];
     struct timespec ts;
@@ -119,7 +119,7 @@
 
         ASSERT_EQ(log_msg.entry.pid, pid);
 
-        if ((int)log_msg.id() != LOG_ID_MAIN) {
+        if ((int)log_msg.id() != LOG_ID_CRASH) {
             continue;
         }
 
diff --git a/libnl_2/.gitignore b/libnl_2/.gitignore
new file mode 100644
index 0000000..d4ca744
--- /dev/null
+++ b/libnl_2/.gitignore
@@ -0,0 +1,2 @@
+include/netlink/version.h.in
+cscope.*
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
new file mode 100644
index 0000000..3721fc6
--- /dev/null
+++ b/libnl_2/Android.mk
@@ -0,0 +1,39 @@
+#######################################
+# * 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
new file mode 100644
index 0000000..14db6db
--- /dev/null
+++ b/libnl_2/README
@@ -0,0 +1,88 @@
+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
new file mode 100644
index 0000000..2ef7590
--- /dev/null
+++ b/libnl_2/attr.c
@@ -0,0 +1,239 @@
+/*
+ * 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
new file mode 100644
index 0000000..c21974d
--- /dev/null
+++ b/libnl_2/cache.c
@@ -0,0 +1,37 @@
+/*
+ * 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
new file mode 100644
index 0000000..9764de6
--- /dev/null
+++ b/libnl_2/dbg.c
@@ -0,0 +1,12 @@
+#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
new file mode 100644
index 0000000..1beee6e
--- /dev/null
+++ b/libnl_2/genl/family.c
@@ -0,0 +1,44 @@
+/*
+ * 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
new file mode 100644
index 0000000..1a39c6a
--- /dev/null
+++ b/libnl_2/genl/genl.c
@@ -0,0 +1,302 @@
+/*
+ * 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
new file mode 100644
index 0000000..48dcab4
--- /dev/null
+++ b/libnl_2/handlers.c
@@ -0,0 +1,90 @@
+/*
+ * 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
new file mode 100644
index 0000000..1303e8a
--- /dev/null
+++ b/libnl_2/msg.c
@@ -0,0 +1,150 @@
+/*
+ * 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
new file mode 100644
index 0000000..ee3d600
--- /dev/null
+++ b/libnl_2/netlink.c
@@ -0,0 +1,273 @@
+/*
+ * 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
new file mode 100644
index 0000000..c53accf
--- /dev/null
+++ b/libnl_2/object.c
@@ -0,0 +1,33 @@
+/*
+ * 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
new file mode 100644
index 0000000..e94eb9e
--- /dev/null
+++ b/libnl_2/socket.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <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);
+}
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index f84a28a..26b9a3e 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -39,7 +39,7 @@
 #include "codeflinger/ARMAssembler.h"
 #elif defined(__aarch64__)
 #include "codeflinger/Arm64Assembler.h"
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 #include "codeflinger/MIPSAssembler.h"
 #endif
 //#include "codeflinger/ARMAssemblerOptimizer.h"
@@ -59,7 +59,7 @@
 #   define ANDROID_CODEGEN      ANDROID_CODEGEN_GENERATED
 #endif
 
-#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
+#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)
 #   define ANDROID_ARM_CODEGEN  1
 #else
 #   define ANDROID_ARM_CODEGEN  0
@@ -73,7 +73,7 @@
  */
 #define DEBUG_NEEDS  0
 
-#ifdef __mips__
+#if defined( __mips__) && !defined(__LP64__)
 #define ASSEMBLY_SCRATCH_SIZE   4096
 #elif defined(__aarch64__)
 #define ASSEMBLY_SCRATCH_SIZE   8192
@@ -134,7 +134,7 @@
 #elif defined(__aarch64__)
 extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
 extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__mips__)
+#elif defined(__mips__)  && !defined(__LP64__)
 extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
 #endif
 
@@ -2175,7 +2175,7 @@
 
 void scanline_t32cb16blend(context_t* c)
 {
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__mips__) || defined(__aarch64__)))
+#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)))
     int32_t x = c->iterators.xl;
     size_t ct = c->iterators.xr - x;
     int32_t y = c->iterators.y;
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index e9f6c61..46c1ccc 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -52,7 +52,7 @@
     GGLAssembler assembler( new ARMAssembler(a) );
 #endif
 
-#if defined(__mips__)
+#if defined(__mips__) && !defined(__LP64__)
     GGLAssembler assembler( new ArmToMipsAssembler(a) );
 #endif
 
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 1c48619..9a50147 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -43,7 +43,7 @@
 	VectorImpl.cpp \
 	misc.cpp
 
-host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
 
 ifeq ($(HOST_OS),windows)
 ifeq ($(strip $(USE_CYGWIN),),)
@@ -69,6 +69,7 @@
 LOCAL_MODULE:= libutils
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(host_commonCflags)
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -99,6 +100,7 @@
 ifeq ($(TARGET_ARCH),mips)
 LOCAL_CFLAGS += -DALIGN_DOUBLE
 endif
+LOCAL_CFLAGS += -Werror
 
 LOCAL_C_INCLUDES += \
 		bionic/libc/private \
@@ -126,7 +128,8 @@
         libbacktrace \
         libcutils \
         libdl \
-        liblog \
+        liblog
+LOCAL_CFLAGS := -Werror
 
 include external/stlport/libstlport.mk
 
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 660917b..f00bf14 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -28,7 +28,7 @@
 namespace android {
 
 // BlobCache::Header::mMagicNumber value
-static const uint32_t blobCacheMagic = '_Bb$';
+static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
 
 // BlobCache::Header::mBlobCacheVersion value
 static const uint32_t blobCacheVersion = 1;
@@ -49,7 +49,7 @@
     mRandState[1] = (now >> 16) & 0xFFFF;
     mRandState[2] = (now >> 32) & 0xFFFF;
 #endif
-    ALOGV("initializing random seed using %lld", now);
+    ALOGV("initializing random seed using %lld", (unsigned long long)now);
 }
 
 void BlobCache::set(const void* key, size_t keySize, const void* value,
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 933e7aa..be4b14f 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -23,7 +23,13 @@
 #include <utils/FileMap.h>
 #include <utils/Log.h>
 
+#if defined(HAVE_WIN32_FILEMAP) && !defined(__USE_MINGW_ANSI_STDIO)
+# define PRId32 "I32d"
+# define PRIx32 "I32x"
+# define PRId64 "I64d"
+#else
 #include <inttypes.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -169,8 +175,8 @@
             goto try_again;
         }
 
-        ALOGE("mmap(%" PRId64 ",%zu) failed: %s\n",
-            adjOffset, adjLength, strerror(errno));
+        ALOGE("mmap(%lld,%zu) failed: %s\n",
+            (long long)adjOffset, adjLength, strerror(errno));
         return false;
     }
     mBasePtr = ptr;
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
index a07a291..8b90696 100644
--- a/libutils/LinearAllocator.cpp
+++ b/libutils/LinearAllocator.cpp
@@ -92,7 +92,7 @@
         : mNextPage(0)
     {}
 
-    void* operator new(size_t size, void* buf) { return buf; }
+    void* operator new(size_t /*size*/, void* buf) { return buf; }
 
     void* start() {
         return (void*) (((size_t)this) + sizeof(Page));
@@ -103,7 +103,7 @@
     }
 
 private:
-    Page(const Page& other) {}
+    Page(const Page& /*other*/) {}
     Page* mNextPage;
 };
 
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 385c226..02907ad 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,6 +17,14 @@
 #define LOG_TAG "RefBase"
 // #define LOG_NDEBUG 0
 
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <typeinfo>
+#include <unistd.h>
+
 #include <utils/RefBase.h>
 
 #include <utils/Atomic.h>
@@ -24,13 +32,9 @@
 #include <utils/Log.h>
 #include <utils/threads.h>
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <typeinfo>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
 
 // compile with refcounting debugging enabled
 #define DEBUG_REFS                      0
@@ -388,7 +392,7 @@
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->addWeakRef(id);
-    const int32_t c = android_atomic_inc(&impl->mWeak);
+    const int32_t c __unused = android_atomic_inc(&impl->mWeak);
     ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
 }
 
@@ -615,7 +619,7 @@
 {
 }
 
-bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
 {
     return (flags&FIRST_INC_STRONG) ? true : false;
 }
@@ -626,13 +630,15 @@
 
 // ---------------------------------------------------------------------------
 
-void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
 #if DEBUG_REFS
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
     for (size_t i=0 ; i<n ; i++) {
         renamer(i);
     }
-#endif
 }
+#else
+void RefBase::renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
+#endif
 
 void RefBase::renameRefId(weakref_type* ref,
         const void* old_id, const void* new_id) {
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index b1708d6..8c7b596 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -21,7 +21,9 @@
 #include <stdio.h>
 
 /* for PRId64 */
+#ifndef __STDC_FORMAT_MACROS
 #define __STDC_FORMAT_MACROS 1
+#endif
 #include <inttypes.h>
 
 #include <utils/Log.h>
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 3bdc349..91efdaa 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -66,8 +66,6 @@
         return getEmptyString();
     }
 
-    const uint8_t* const u8end = u8cur + u8len;
-
     SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
     if (buf) {
         u8cur = (const uint8_t*) u8str;
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 8acb4d4..49340bb 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -551,7 +551,6 @@
 {
     const char* lastSlash;
     const char* lastDot;
-    int extLen;
     const char* const str = mString;
 
     // only look at the filename
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 413250f..dbad581 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -68,13 +68,7 @@
  */
 #define DEBUG_TIMESTAMP         0
 
-static const char *gettime_method_names[] = {
-    "clock_gettime",
-    "ioctl",
-    "systemTime",
-};
-
-#if DEBUG_TIMESTAMP
+#if DEBUG_TIMESTAMP && defined(ARCH_ARM)
 static inline void checkTimeStamps(int64_t timestamp,
                                    int64_t volatile *prevTimestampPtr,
                                    int volatile *prevMethodPtr,
@@ -85,11 +79,16 @@
      * gettid, and int64_t is different on the ARM platform
      * (ie long vs long long).
      */
-#ifdef ARCH_ARM
     int64_t prevTimestamp = *prevTimestampPtr;
     int prevMethod = *prevMethodPtr;
 
     if (timestamp < prevTimestamp) {
+        static const char *gettime_method_names[] = {
+            "clock_gettime",
+            "ioctl",
+            "systemTime",
+        };
+
         ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
               prevTimestamp, gettime_method_names[prevMethod],
               timestamp, gettime_method_names[curMethod],
@@ -99,7 +98,6 @@
     // write is interrupted or not observed as a whole.
     *prevTimestampPtr = timestamp;
     *prevMethodPtr = curMethod;
-#endif
 }
 #else
 #define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index ff74914..cc7fe89 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -17,16 +17,11 @@
 // #define LOG_NDEBUG 0
 #define LOG_TAG "libutils.threads"
 
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <cutils/sched_policy.h>
-
+#include <assert.h>
+#include <errno.h>
+#include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <memory.h>
-#include <errno.h>
-#include <assert.h>
 #include <unistd.h>
 
 #if defined(HAVE_PTHREADS)
@@ -47,6 +42,17 @@
 #include <sys/prctl.h>
 #endif
 
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <cutils/sched_policy.h>
+
+#ifdef HAVE_ANDROID_OS
+# define __android_unused
+#else
+# define __android_unused __attribute__((__unused__))
+#endif
+
 /*
  * ===========================================================================
  *      Thread wrappers
@@ -119,7 +125,7 @@
 
 int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                                void *userData,
-                               const char* threadName,
+                               const char* threadName __android_unused,
                                int32_t threadPriority,
                                size_t threadStackSize,
                                android_thread_id_t *threadId)
@@ -251,9 +257,9 @@
 
 int androidCreateRawThreadEtc(android_thread_func_t fn,
                                void *userData,
-                               const char* threadName,
-                               int32_t threadPriority,
-                               size_t threadStackSize,
+                               const char* /*threadName*/,
+                               int32_t /*threadPriority*/,
+                               size_t /*threadStackSize*/,
                                android_thread_id_t *threadId)
 {
     return doCreateThread(  fn, userData, threadId);
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index a431e92..4687d4d 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -32,9 +32,9 @@
 #include <windows.h>
 #endif
 
+#if defined(HAVE_ANDROID_OS)
 nsecs_t systemTime(int clock)
 {
-#if defined(HAVE_ANDROID_OS)
     static const clockid_t clocks[] = {
             CLOCK_REALTIME,
             CLOCK_MONOTONIC,
@@ -46,7 +46,10 @@
     t.tv_sec = t.tv_nsec = 0;
     clock_gettime(clocks[clock], &t);
     return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
 #else
+nsecs_t systemTime(int /*clock*/)
+{
     // Clock support varies widely across hosts. Mac OS doesn't support
     // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
     // is windows.
@@ -54,8 +57,8 @@
     t.tv_sec = t.tv_usec = 0;
     gettimeofday(&t, NULL);
     return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
-#endif
 }
+#endif
 
 int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
 {
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index a66e3bb..fe8887d 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -576,7 +576,7 @@
 char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
     const uint8_t* const u8end = src + srcLen;
     const uint8_t* u8cur = src;
-    const uint16_t* const u16end = dst + dstLen;
+    const char16_t* const u16end = dst + dstLen;
     char16_t* u16cur = dst;
 
     while (u8cur < u8end && u16cur < u16end) {
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
index 7202123..dac4e2c 100644
--- a/libutils/tests/BlobCache_test.cpp
+++ b/libutils/tests/BlobCache_test.cpp
@@ -44,7 +44,7 @@
 };
 
 TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
     ASSERT_EQ('e', buf[0]);
@@ -54,7 +54,7 @@
 }
 
 TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
-    char buf[2] = { 0xee, 0xee };
+    unsigned char buf[2] = { 0xee, 0xee };
     mBC->set("ab", 2, "cd", 2);
     mBC->set("ef", 2, "gh", 2);
     ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
@@ -66,7 +66,7 @@
 }
 
 TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
-    char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
     ASSERT_EQ(0xee, buf[0]);
@@ -78,7 +78,7 @@
 }
 
 TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
-    char buf[3] = { 0xee, 0xee, 0xee };
+    unsigned char buf[3] = { 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
     ASSERT_EQ(0xee, buf[0]);
@@ -92,7 +92,7 @@
 }
 
 TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     mBC->set("abcd", 4, "ijkl", 4);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -103,7 +103,7 @@
 }
 
 TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
-    char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -115,7 +115,7 @@
 
 TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
     char key[MAX_KEY_SIZE+1];
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
         key[i] = 'a';
     }
@@ -165,7 +165,7 @@
 
 TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
     char key[MAX_KEY_SIZE];
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     for (int i = 0; i < MAX_KEY_SIZE; i++) {
         key[i] = 'a';
     }
@@ -214,7 +214,7 @@
 }
 
 TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
-    char buf[1] = { 0xee };
+    unsigned char buf[1] = { 0xee };
     mBC->set("x", 1, "y", 1);
     ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
     ASSERT_EQ('y', buf[0]);
@@ -282,7 +282,7 @@
 };
 
 TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
     roundTrip();
     ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
@@ -348,7 +348,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
@@ -365,7 +365,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
@@ -384,7 +384,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
@@ -403,7 +403,7 @@
 }
 
 TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
-    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
     mBC->set("abcd", 4, "efgh", 4);
 
     size_t size = mBC->getFlattenedSize();
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index 1d48fea..705caa5 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -42,6 +42,7 @@
 LOCAL_STATIC_LIBRARIES := libz libutils
 LOCAL_MODULE:= libziparchive-host
 LOCAL_CFLAGS := -Werror
+LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6781ebe..128bad4 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -35,57 +35,173 @@
 
 #include "ziparchive/zip_archive.h"
 
-// This is for windows. If we don't open a file in binary mode, weirds
+// This is for windows. If we don't open a file in binary mode, weird
 // things will happen.
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 
-/*
- * Zip file constants.
- */
-static const uint32_t kEOCDSignature    = 0x06054b50;
-static const uint32_t kEOCDLen          = 2;
-static const uint32_t kEOCDNumEntries   = 8;              // offset to #of entries in file
-static const uint32_t kEOCDSize         = 12;             // size of the central directory
-static const uint32_t kEOCDFileOffset   = 16;             // offset to central directory
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+    TypeName(); \
+    TypeName(const TypeName&); \
+    void operator=(const TypeName&)
 
-static const uint32_t kMaxCommentLen    = 65535;          // longest possible in ushort
-static const uint32_t kMaxEOCDSearch    = (kMaxCommentLen + kEOCDLen);
+// The "end of central directory" (EOCD) record. Each archive
+// contains exactly once such record which appears at the end of
+// the archive. It contains archive wide information like the
+// number of entries in the archive and the offset to the central
+// directory of the offset.
+struct EocdRecord {
+  static const uint32_t kSignature = 0x06054b50;
 
-static const uint32_t kLFHSignature     = 0x04034b50;
-static const uint32_t kLFHLen           = 30;             // excluding variable-len fields
-static const uint32_t kLFHGPBFlags      = 6;              // general purpose bit flags
-static const uint32_t kLFHCRC           = 14;             // offset to CRC
-static const uint32_t kLFHCompLen       = 18;             // offset to compressed length
-static const uint32_t kLFHUncompLen     = 22;             // offset to uncompressed length
-static const uint32_t kLFHNameLen       = 26;             // offset to filename length
-static const uint32_t kLFHExtraLen      = 28;             // offset to extra length
+  // End of central directory signature, should always be
+  // |kSignature|.
+  uint32_t eocd_signature;
+  // The number of the current "disk", i.e, the "disk" that this
+  // central directory is on.
+  //
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that disk_num == 1.
+  uint16_t disk_num;
+  // The disk where the central directory starts.
+  //
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that cd_start_disk == 1.
+  uint16_t cd_start_disk;
+  // The number of central directory records on this disk.
+  //
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that num_records_on_disk == num_records.
+  uint16_t num_records_on_disk;
+  // The total number of central directory records.
+  uint16_t num_records;
+  // The size of the central directory (in bytes).
+  uint32_t cd_size;
+  // The offset of the start of the central directory, relative
+  // to the start of the file.
+  uint32_t cd_start_offset;
+  // Length of the central directory comment.
+  uint16_t comment_length;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+} __attribute__((packed));
 
-static const uint32_t kCDESignature     = 0x02014b50;
-static const uint32_t kCDELen           = 46;             // excluding variable-len fields
-static const uint32_t kCDEMethod        = 10;             // offset to compression method
-static const uint32_t kCDEModWhen       = 12;             // offset to modification timestamp
-static const uint32_t kCDECRC           = 16;             // offset to entry CRC
-static const uint32_t kCDECompLen       = 20;             // offset to compressed length
-static const uint32_t kCDEUncompLen     = 24;             // offset to uncompressed length
-static const uint32_t kCDENameLen       = 28;             // offset to filename length
-static const uint32_t kCDEExtraLen      = 30;             // offset to extra length
-static const uint32_t kCDECommentLen    = 32;             // offset to comment length
-static const uint32_t kCDELocalOffset   = 42;             // offset to local hdr
+// A structure representing the fixed length fields for a single
+// record in the central directory of the archive. In addition to
+// the fixed length fields listed here, each central directory
+// record contains a variable length "file_name" and "extra_field"
+// whose lengths are given by |file_name_length| and |extra_field_length|
+// respectively.
+struct CentralDirectoryRecord {
+  static const uint32_t kSignature = 0x02014b50;
 
-static const uint32_t kDDOptSignature   = 0x08074b50;     // *OPTIONAL* data descriptor signature
-static const uint32_t kDDSignatureLen   = 4;
-static const uint32_t kDDLen            = 12;
-static const uint32_t kDDMaxLen         = 16;             // max of 16 bytes with a signature, 12 bytes without
-static const uint32_t kDDCrc32          = 0;              // offset to crc32
-static const uint32_t kDDCompLen        = 4;              // offset to compressed length
-static const uint32_t kDDUncompLen      = 8;              // offset to uncompressed length
+  // The start of record signature. Must be |kSignature|.
+  uint32_t record_signature;
+  // Tool version. Ignored by this implementation.
+  uint16_t version_made_by;
+  // Tool version. Ignored by this implementation.
+  uint16_t version_needed;
+  // The "general purpose bit flags" for this entry. The only
+  // flag value that we currently check for is the "data descriptor"
+  // flag.
+  uint16_t gpb_flags;
+  // The compression method for this entry, one of |kCompressStored|
+  // and |kCompressDeflated|.
+  uint16_t compression_method;
+  // The file modification time and date for this entry.
+  uint16_t last_mod_time;
+  uint16_t last_mod_date;
+  // The CRC-32 checksum for this entry.
+  uint32_t crc32;
+  // The compressed size (in bytes) of this entry.
+  uint32_t compressed_size;
+  // The uncompressed size (in bytes) of this entry.
+  uint32_t uncompressed_size;
+  // The length of the entry file name in bytes. The file name
+  // will appear immediately after this record.
+  uint16_t file_name_length;
+  // The length of the extra field info (in bytes). This data
+  // will appear immediately after the entry file name.
+  uint16_t extra_field_length;
+  // The length of the entry comment (in bytes). This data will
+  // appear immediately after the extra field.
+  uint16_t comment_length;
+  // The start disk for this entry. Ignored by this implementation).
+  uint16_t file_start_disk;
+  // File attributes. Ignored by this implementation.
+  uint16_t internal_file_attributes;
+  // File attributes. Ignored by this implementation.
+  uint32_t external_file_attributes;
+  // The offset to the local file header for this entry, from the
+  // beginning of this archive.
+  uint32_t local_file_header_offset;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+} __attribute__((packed));
 
-static const uint32_t kGPBDDFlagMask    = 0x0008;         // mask value that signifies that the entry has a DD
+// The local file header for a given entry. This duplicates information
+// present in the central directory of the archive. It is an error for
+// the information here to be different from the central directory
+// information for a given entry.
+struct LocalFileHeader {
+  static const uint32_t kSignature = 0x04034b50;
 
+  // The local file header signature, must be |kSignature|.
+  uint32_t lfh_signature;
+  // Tool version. Ignored by this implementation.
+  uint16_t version_needed;
+  // The "general purpose bit flags" for this entry. The only
+  // flag value that we currently check for is the "data descriptor"
+  // flag.
+  uint16_t gpb_flags;
+  // The compression method for this entry, one of |kCompressStored|
+  // and |kCompressDeflated|.
+  uint16_t compression_method;
+  // The file modification time and date for this entry.
+  uint16_t last_mod_time;
+  uint16_t last_mod_date;
+  // The CRC-32 checksum for this entry.
+  uint32_t crc32;
+  // The compressed size (in bytes) of this entry.
+  uint32_t compressed_size;
+  // The uncompressed size (in bytes) of this entry.
+  uint32_t uncompressed_size;
+  // The length of the entry file name in bytes. The file name
+  // will appear immediately after this record.
+  uint16_t file_name_length;
+  // The length of the extra field info (in bytes). This data
+  // will appear immediately after the entry file name.
+  uint16_t extra_field_length;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+} __attribute__((packed));
+
+struct DataDescriptor {
+  // The *optional* data descriptor start signature.
+  static const uint32_t kOptSignature = 0x08074b50;
+
+  // CRC-32 checksum of the entry.
+  uint32_t crc32;
+  // Compressed size of the entry.
+  uint32_t compressed_size;
+  // Uncompressed size of the entry.
+  uint32_t uncompressed_size;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+} __attribute__((packed));
+
+#undef DISALLOW_IMPLICIT_CONSTRUCTORS
+
+static const uint32_t kGPBDDFlagMask = 0x0008;         // mask value that signifies that the entry has a DD
 static const uint32_t kMaxErrorLen = 1024;
 
+// The maximum size of a central directory or a file
+// comment in bytes.
+static const uint32_t kMaxCommentLen = 65535;
+
+// The maximum number of bytes to scan backwards for the EOCD start.
+static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
+
 static const char* kErrorMessages[] = {
   "Unknown return code.",
   "Iteration ended",
@@ -311,39 +427,21 @@
   return 0;
 }
 
-/*
- * Get 2 little-endian bytes.
- */
-static uint16_t get2LE(const uint8_t* src) {
-  return src[0] | (src[1] << 8);
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-static uint32_t get4LE(const uint8_t* src) {
-  uint32_t result;
-
-  result = src[0];
-  result |= src[1] << 8;
-  result |= src[2] << 16;
-  result |= src[3] << 24;
-
-  return result;
-}
-
 static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
                                     ZipArchive* archive, off64_t file_length,
-                                    uint32_t read_amount, uint8_t* scan_buffer) {
+                                    off64_t read_amount, uint8_t* scan_buffer) {
   const off64_t search_start = file_length - read_amount;
 
   if (lseek64(fd, search_start, SEEK_SET) != search_start) {
-    ALOGW("Zip: seek %" PRId64 " failed: %s", (int64_t)search_start, strerror(errno));
+    ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
+          strerror(errno));
     return kIoError;
   }
-  ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount));
-  if (actual != (ssize_t) read_amount) {
-    ALOGW("Zip: read %" PRIu32 " failed: %s", read_amount, strerror(errno));
+  ssize_t actual = TEMP_FAILURE_RETRY(
+      read(fd, scan_buffer, static_cast<size_t>(read_amount)));
+  if (actual != static_cast<ssize_t>(read_amount)) {
+    ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
+          strerror(errno));
     return kIoError;
   }
 
@@ -353,9 +451,10 @@
    * doing an initial minimal read; if we don't find it, retry with a
    * second read as above.)
    */
-  int i;
-  for (i = read_amount - kEOCDLen; i >= 0; i--) {
-    if (scan_buffer[i] == 0x50 && get4LE(&scan_buffer[i]) == kEOCDSignature) {
+  int i = read_amount - sizeof(EocdRecord);
+  for (; i >= 0; i--) {
+    if (scan_buffer[i] == 0x50 &&
+        ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
       ALOGV("+++ Found EOCD at buf+%d", i);
       break;
     }
@@ -366,46 +465,52 @@
   }
 
   const off64_t eocd_offset = search_start + i;
-  const uint8_t* eocd_ptr = scan_buffer + i;
-
-  assert(eocd_offset < file_length);
+  const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
+  /*
+   * Verify that there's no trailing space at the end of the central directory
+   * and its comment.
+   */
+  const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
+      + eocd->comment_length;
+  if (calculated_length != file_length) {
+    ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
+          static_cast<int64_t>(file_length - calculated_length));
+    return kInvalidFile;
+  }
 
   /*
    * Grab the CD offset and size, and the number of entries in the
-   * archive.  Verify that they look reasonable. Widen dir_size and
-   * dir_offset to the file offset type.
+   * archive and verify that they look reasonable.
    */
-  const uint16_t num_entries = get2LE(eocd_ptr + kEOCDNumEntries);
-  const off64_t dir_size = get4LE(eocd_ptr + kEOCDSize);
-  const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset);
-
-  if (dir_offset + dir_size > eocd_offset) {
-    ALOGW("Zip: bad offsets (dir %" PRId64 ", size %" PRId64 ", eocd %" PRId64 ")",
-        (int64_t)dir_offset, (int64_t)dir_size, (int64_t)eocd_offset);
+  if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
+    ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
+        eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
     return kInvalidOffset;
   }
-  if (num_entries == 0) {
+  if (eocd->num_records == 0) {
     ALOGW("Zip: empty archive?");
     return kEmptyArchive;
   }
 
-  ALOGV("+++ num_entries=%d dir_size=%" PRId64 " dir_offset=%" PRId64,
-        num_entries, (int64_t)dir_size, (int64_t)dir_offset);
+  ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
+        eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
 
   /*
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size,
-                                         true /* read only */, debug_file_name);
+  android::FileMap* map = MapFileSegment(fd,
+      static_cast<off64_t>(eocd->cd_start_offset),
+      static_cast<size_t>(eocd->cd_size),
+      true /* read only */, debug_file_name);
   if (map == NULL) {
     archive->directory_map = NULL;
     return kMmapFailed;
   }
 
   archive->directory_map = map;
-  archive->num_entries = num_entries;
-  archive->directory_offset = dir_offset;
+  archive->num_entries = eocd->num_records;
+  archive->directory_offset = eocd->cd_start_offset;
 
   return 0;
 }
@@ -431,12 +536,12 @@
   }
 
   if (file_length > (off64_t) 0xffffffff) {
-    ALOGV("Zip: zip file too long %" PRId64, (int64_t)file_length);
+    ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
 
-  if (file_length < (int64_t) kEOCDLen) {
-    ALOGV("Zip: length %" PRId64 " is too small to be zip", (int64_t)file_length);
+  if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
+    ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
 
@@ -452,12 +557,12 @@
    *
    * We start by pulling in the last part of the file.
    */
-  uint32_t read_amount = kMaxEOCDSearch;
-  if (file_length < (off64_t) read_amount) {
+  off64_t read_amount = kMaxEOCDSearch;
+  if (file_length < read_amount) {
     read_amount = file_length;
   }
 
-  uint8_t* scan_buffer = (uint8_t*) malloc(read_amount);
+  uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
   int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
                                         file_length, read_amount, scan_buffer);
 
@@ -473,9 +578,9 @@
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
   int32_t result = -1;
-  const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
-  size_t cd_length = archive->directory_map->getDataLength();
-  uint16_t num_entries = archive->num_entries;
+  const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
+  const size_t cd_length = archive->directory_map->getDataLength();
+  const uint16_t num_entries = archive->num_entries;
 
   /*
    * Create hash table.  We have a minimum 75% load factor, possibly as
@@ -490,39 +595,43 @@
    * Walk through the central directory, adding entries to the hash
    * table and verifying values.
    */
+  const uint8_t* const cd_end = cd_ptr + cd_length;
   const uint8_t* ptr = cd_ptr;
   for (uint16_t i = 0; i < num_entries; i++) {
-    if (get4LE(ptr) != kCDESignature) {
+    const CentralDirectoryRecord* cdr =
+        reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+    if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
       ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
       goto bail;
     }
 
-    if (ptr + kCDELen > cd_ptr + cd_length) {
+    if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
       ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
       goto bail;
     }
 
-    const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
+    const off64_t local_header_offset = cdr->local_file_header_offset;
     if (local_header_offset >= archive->directory_offset) {
       ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
       goto bail;
     }
 
-    const uint16_t file_name_length = get2LE(ptr + kCDENameLen);
-    const uint16_t extra_length = get2LE(ptr + kCDEExtraLen);
-    const uint16_t comment_length = get2LE(ptr + kCDECommentLen);
+    const uint16_t file_name_length = cdr->file_name_length;
+    const uint16_t extra_length = cdr->extra_field_length;
+    const uint16_t comment_length = cdr->comment_length;
 
     /* add the CDE filename to the hash table */
+    const char* file_name = reinterpret_cast<const char *>(ptr + sizeof(CentralDirectoryRecord));
     const int add_result = AddToHash(archive->hash_table,
-        archive->hash_table_size, (const char*) ptr + kCDELen, file_name_length);
+        archive->hash_table_size, file_name, file_name_length);
     if (add_result) {
       ALOGW("Zip: Error adding entry to hash table %d", add_result);
       result = add_result;
       goto bail;
     }
 
-    ptr += kCDELen + file_name_length + extra_length + comment_length;
-    if ((size_t)(ptr - cd_ptr) > cd_length) {
+    ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
+    if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
       ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
           ptr - cd_ptr, cd_length, i);
       goto bail;
@@ -597,21 +706,19 @@
 
 static int32_t UpdateEntryFromDataDescriptor(int fd,
                                              ZipEntry *entry) {
-  uint8_t ddBuf[kDDMaxLen];
+  uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
   ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
   if (actual != sizeof(ddBuf)) {
     return kIoError;
   }
 
-  const uint32_t ddSignature = get4LE(ddBuf);
-  uint16_t ddOffset = 0;
-  if (ddSignature == kDDOptSignature) {
-    ddOffset = 4;
-  }
+  const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
+  const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
 
-  entry->crc32 = get4LE(ddBuf + ddOffset + kDDCrc32);
-  entry->compressed_length = get4LE(ddBuf + ddOffset + kDDCompLen);
-  entry->uncompressed_length = get4LE(ddBuf + ddOffset + kDDUncompLen);
+  entry->crc32 = descriptor->crc32;
+  entry->compressed_length = descriptor->compressed_size;
+  entry->uncompressed_length = descriptor->uncompressed_size;
 
   return 0;
 }
@@ -647,19 +754,22 @@
   // Recover the start of the central directory entry from the filename
   // pointer.  The filename is the first entry past the fixed-size data,
   // so we can just subtract back from that.
-  const unsigned char* ptr = (const unsigned char*) name;
-  ptr -= kCDELen;
+  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+  ptr -= sizeof(CentralDirectoryRecord);
 
   // This is the base of our mmapped region, we have to sanity check that
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
-  const unsigned char* base_ptr = (const unsigned char*)
-    archive->directory_map->getDataPtr();
+  const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
+    archive->directory_map->getDataPtr());
   if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
 
+  const CentralDirectoryRecord *cdr =
+      reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+
   // The offset of the start of the central directory in the zipfile.
   // We keep this lying around so that we can sanity check all our lengths
   // and our per-file structures.
@@ -668,22 +778,22 @@
   // Fill out the compression method, modification time, crc32
   // and other interesting attributes from the central directory. These
   // will later be compared against values from the local file header.
-  data->method = get2LE(ptr + kCDEMethod);
-  data->mod_time = get4LE(ptr + kCDEModWhen);
-  data->crc32 = get4LE(ptr + kCDECRC);
-  data->compressed_length = get4LE(ptr + kCDECompLen);
-  data->uncompressed_length = get4LE(ptr + kCDEUncompLen);
+  data->method = cdr->compression_method;
+  data->mod_time = cdr->last_mod_time;
+  data->crc32 = cdr->crc32;
+  data->compressed_length = cdr->compressed_size;
+  data->uncompressed_length = cdr->uncompressed_size;
 
   // Figure out the local header offset from the central directory. The
   // actual file data will begin after the local header and the name /
   // extra comments.
-  const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
-  if (local_header_offset + (off64_t) kLFHLen >= cd_offset) {
+  const off64_t local_header_offset = cdr->local_file_header_offset;
+  if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
     ALOGW("Zip: bad local hdr offset in zip");
     return kInvalidOffset;
   }
 
-  uint8_t lfh_buf[kLFHLen];
+  uint8_t lfh_buf[sizeof(LocalFileHeader)];
   ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
                                  local_header_offset);
   if (actual != sizeof(lfh_buf)) {
@@ -691,30 +801,25 @@
     return kIoError;
   }
 
-  if (get4LE(lfh_buf) != kLFHSignature) {
+  const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
+
+  if (lfh->lfh_signature != LocalFileHeader::kSignature) {
     ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
-        (int64_t)local_header_offset);
+        static_cast<int64_t>(local_header_offset));
     return kInvalidOffset;
   }
 
   // Paranoia: Match the values specified in the local file header
   // to those specified in the central directory.
-  const uint16_t lfhGpbFlags = get2LE(lfh_buf + kLFHGPBFlags);
-  const uint16_t lfhNameLen = get2LE(lfh_buf + kLFHNameLen);
-  const uint16_t lfhExtraLen = get2LE(lfh_buf + kLFHExtraLen);
-
-  if ((lfhGpbFlags & kGPBDDFlagMask) == 0) {
-    const uint32_t lfhCrc = get4LE(lfh_buf + kLFHCRC);
-    const uint32_t lfhCompLen = get4LE(lfh_buf + kLFHCompLen);
-    const uint32_t lfhUncompLen = get4LE(lfh_buf + kLFHUncompLen);
-
+  if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
     data->has_data_descriptor = 0;
-    if (data->compressed_length != lfhCompLen || data->uncompressed_length != lfhUncompLen
-        || data->crc32 != lfhCrc) {
+    if (data->compressed_length != lfh->compressed_size
+        || data->uncompressed_length != lfh->uncompressed_size
+        || data->crc32 != lfh->crc32) {
       ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
         ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
         data->compressed_length, data->uncompressed_length, data->crc32,
-        lfhCompLen, lfhUncompLen, lfhCrc);
+        lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
       return kInconsistentInformation;
     }
   } else {
@@ -723,9 +828,9 @@
 
   // Check that the local file header name matches the declared
   // name in the central directory.
-  if (lfhNameLen == nameLen) {
-    const off64_t name_offset = local_header_offset + kLFHLen;
-    if (name_offset + lfhNameLen >= cd_offset) {
+  if (lfh->file_name_length == nameLen) {
+    const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
+    if (name_offset + lfh->file_name_length >= cd_offset) {
       ALOGW("Zip: Invalid declared length");
       return kInvalidOffset;
     }
@@ -751,7 +856,8 @@
     return kInconsistentInformation;
   }
 
-  const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
+  const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
+      + lfh->file_name_length + lfh->extra_field_length;
   if (data_offset > cd_offset) {
     ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
     return kInvalidOffset;
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 2eb9318..875b6de 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -140,11 +140,7 @@
   CloseArchive(handle);
 }
 
-TEST(ziparchive, EmptyEntries) {
-  char temp_file_pattern[] = "empty_entries_test_XXXXXX";
-  int fd = mkstemp(temp_file_pattern);
-  ASSERT_NE(-1, fd);
-  const uint32_t data[] = {
+static const uint32_t kEmptyEntriesZip[] = {
       0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
       0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
       0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
@@ -152,8 +148,28 @@
       0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
       0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
       0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
-  const ssize_t file_size = 168;
-  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size)));
+
+static int make_temporary_file(const char* file_name_pattern) {
+  char full_path[1024];
+  // Account for differences between the host and the target.
+  //
+  // TODO: Maybe reuse bionic/tests/TemporaryFile.h.
+  snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern);
+  int fd = mkstemp(full_path);
+  if (fd == -1) {
+    snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern);
+    fd = mkstemp(full_path);
+  }
+
+  return fd;
+}
+
+TEST(ziparchive, EmptyEntries) {
+  char temp_file_pattern[] = "empty_entries_test_XXXXXX";
+  int fd = make_temporary_file(temp_file_pattern);
+  ASSERT_NE(-1, fd);
+  const ssize_t file_size = sizeof(kEmptyEntriesZip);
+  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
 
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
@@ -165,7 +181,7 @@
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
 
   char output_file_pattern[] = "empty_entries_output_XXXXXX";
-  int output_fd = mkstemp(output_file_pattern);
+  int output_fd = make_temporary_file(output_file_pattern);
   ASSERT_NE(-1, output_fd);
   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
 
@@ -177,9 +193,25 @@
   close(output_fd);
 }
 
+TEST(ziparchive, TrailerAfterEOCD) {
+  char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
+  int fd = make_temporary_file(temp_file_pattern);
+  ASSERT_NE(-1, fd);
+
+  // Create a file with 8 bytes of random garbage.
+  static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
+  const ssize_t file_size = sizeof(kEmptyEntriesZip);
+  const ssize_t trailer_size = sizeof(trailer);
+  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
+  ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size)));
+
+  ZipArchiveHandle handle;
+  ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+}
+
 TEST(ziparchive, ExtractToFile) {
   char kTempFilePattern[] = "zip_archive_input_XXXXXX";
-  int fd = mkstemp(kTempFilePattern);
+  int fd = make_temporary_file(kTempFilePattern);
   ASSERT_NE(-1, fd);
   const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
   const ssize_t data_size = sizeof(data);
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
index 614a460..12a2229 100644
--- a/libzipfile/Android.mk
+++ b/libzipfile/Android.mk
@@ -16,6 +16,8 @@
 
 LOCAL_CFLAGS := -Werror
 
+LOCAL_MULTILIB := both
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 # build device static library
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 5d4d29e..015a23d 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -16,11 +16,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# -----------------------------------------------------------------------------
-# Unit tests.
-# -----------------------------------------------------------------------------
-
-test_module := logcat-unit-tests
+test_module_prefix := logcat-
 test_tags := tests
 
 test_c_flags := \
@@ -28,7 +24,29 @@
     -g \
     -Wall -Wextra \
     -Werror \
-    -fno-builtin
+    -fno-builtin \
+    -std=gnu++11
+
+# -----------------------------------------------------------------------------
+# Benchmarks (actually a gTest where the result code does not matter)
+# ----------------------------------------------------------------------------
+
+benchmark_src_files := \
+    logcat_benchmark.cpp
+
+# Build benchmarks for the device. Run with:
+#   adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)benchmarks
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SRC_FILES := $(benchmark_src_files)
+include $(BUILD_NATIVE_TEST)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
 
 test_src_files := \
     logcat_test.cpp \
@@ -36,7 +54,7 @@
 # Build tests for the device (with .so). Run with:
 #   adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
 include $(CLEAR_VARS)
-LOCAL_MODULE := $(test_module)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
new file mode 100644
index 0000000..be815be
--- /dev/null
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+static const char begin[] = "--------- beginning of ";
+
+TEST(logcat, sorted_order) {
+    FILE *fp;
+
+    ASSERT_TRUE(NULL != (fp = popen(
+      "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+      "r")));
+
+    class timestamp {
+    private:
+        int month;
+        int day;
+        int hour;
+        int minute;
+        int second;
+        int millisecond;
+        bool ok;
+
+    public:
+        void init(const char *buffer)
+        {
+            ok = false;
+            if (buffer != NULL) {
+                ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
+                    &month, &day, &hour, &minute, &second, &millisecond) == 6;
+            }
+        }
+
+        timestamp(const char *buffer)
+        {
+            init(buffer);
+        }
+
+        bool operator< (timestamp &T)
+        {
+            return !ok || !T.ok
+             || (month < T.month)
+             || ((month == T.month)
+              && ((day < T.day)
+               || ((day == T.day)
+                && ((hour < T.hour)
+                 || ((hour == T.hour)
+                  && ((minute < T.minute)
+                   || ((minute == T.minute)
+                    && ((second < T.second)
+                     || ((second == T.second)
+                      && (millisecond < T.millisecond))))))))));
+        }
+
+        bool valid(void)
+        {
+            return ok;
+        }
+    } 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);
+        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);
+
+    static const int max_ok = 2;
+
+    // Allow few fails, happens with readers active
+    fprintf(stderr, "%s: %d/%d out of order entries\n",
+            (next_lt_last)
+                ? ((next_lt_last <= max_ok)
+                    ? "WARNING"
+                    : "ERROR")
+                : "INFO",
+            next_lt_last, count);
+
+    EXPECT_GE(max_ok, next_lt_last);
+
+    // sample statistically too small
+    EXPECT_LT(100, count);
+}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 2e8ae8b..9b316d1 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -17,6 +17,7 @@
 #include <ctype.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <gtest/gtest.h>
@@ -41,99 +42,6 @@
 
 static const char begin[] = "--------- beginning of ";
 
-TEST(logcat, sorted_order) {
-    FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
-      "r")));
-
-    class timestamp {
-    private:
-        int month;
-        int day;
-        int hour;
-        int minute;
-        int second;
-        int millisecond;
-        bool ok;
-
-    public:
-        void init(const char *buffer)
-        {
-            ok = false;
-            if (buffer != NULL) {
-                ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
-                    &month, &day, &hour, &minute, &second, &millisecond) == 6;
-            }
-        }
-
-        timestamp(const char *buffer)
-        {
-            init(buffer);
-        }
-
-        bool operator< (timestamp &T)
-        {
-            return !ok || !T.ok
-             || (month < T.month)
-             || ((month == T.month)
-              && ((day < T.day)
-               || ((day == T.day)
-                && ((hour < T.hour)
-                 || ((hour == T.hour)
-                  && ((minute < T.minute)
-                   || ((minute == T.minute)
-                    && ((second < T.second)
-                     || ((second == T.second)
-                      && (millisecond < T.millisecond))))))))));
-        }
-
-        bool valid(void)
-        {
-            return ok;
-        }
-    } 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);
-        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);
-
-    EXPECT_EQ(0, next_lt_last);
-
-    EXPECT_LT(100, count);
-}
-
 TEST(logcat, buckets) {
     FILE *fp;
 
@@ -362,9 +270,10 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(logcat, get_) {
+TEST(logcat, get_size) {
     FILE *fp;
 
+    // NB: crash log only available in user space
     ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -g 2>/dev/null",
       "r")));
@@ -375,13 +284,49 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         int size, consumed, max, payload;
+        char size_mult, consumed_mult;
+        long full_size, full_consumed;
 
         size = consumed = max = payload = 0;
-        if ((4 == sscanf(buffer, "%*s ring buffer is %dKb (%dKb consumed),"
-                                 " max entry is %db, max payload is %db",
-                                 &size, &consumed, &max, &payload))
-         && ((size * 3) >= consumed)
-         && ((size * 1024) > max)
+        // NB: crash log can be very small, not hit a Kb of consumed space
+        //     doubly lucky we are not including it.
+        if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed),"
+                                " max entry is %db, max payload is %db",
+                                &size, &size_mult, &consumed, &consumed_mult,
+                                &max, &payload)) {
+            fprintf(stderr, "WARNING: Parse error: %s", buffer);
+            continue;
+        }
+        full_size = size;
+        switch(size_mult) {
+        case 'G':
+            full_size *= 1024;
+            /* FALLTHRU */
+        case 'M':
+            full_size *= 1024;
+            /* FALLTHRU */
+        case 'K':
+            full_size *= 1024;
+            break;
+        }
+        full_consumed = consumed;
+        switch(consumed_mult) {
+        case 'G':
+            full_consumed *= 1024;
+            /* FALLTHRU */
+        case 'M':
+            full_consumed *= 1024;
+            /* FALLTHRU */
+        case 'K':
+            full_consumed *= 1024;
+            break;
+        }
+        EXPECT_GT((full_size * 9) / 4, full_consumed);
+        EXPECT_GT(full_size, max);
+        EXPECT_GT(max, payload);
+
+        if ((((full_size * 9) / 4) >= full_consumed)
+         && (full_size > max)
          && (max > payload)) {
             ++count;
         }
@@ -649,7 +594,7 @@
 
     char buffer[5120];
 
-    snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list);
+    snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
     fp = popen(buffer, "r");
     if (fp == NULL) {
         fprintf(stderr, "ERROR: %s\n", buffer);
@@ -662,10 +607,10 @@
             ++buf;
         }
         char *end = buf + strlen(buf);
-        while (isspace(*--end) && (end >= buf)) {
+        while ((end > buf) && isspace(*--end)) {
             *end = '\0';
         }
-        if (end < buf) {
+        if (end <= buf) {
             continue;
         }
         fprintf(stderr, "%s\n", buf);
@@ -679,7 +624,7 @@
     char *list = NULL;
     char *adjust = NULL;
 
-    ASSERT_EQ(true, get_white_black(&list));
+    get_white_black(&list);
 
     static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
     ASSERT_EQ(true, set_white_black(adjustment));
@@ -696,8 +641,8 @@
     adjust = NULL;
 
     ASSERT_EQ(true, set_white_black(list));
-    ASSERT_EQ(true, get_white_black(&adjust));
-    EXPECT_STREQ(list, adjust);
+    get_white_black(&adjust);
+    EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
     free(adjust);
     adjust = NULL;
 
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 9d7d152..d7088b4 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -74,9 +74,9 @@
 int CommandListener::ClearCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
     setname();
-    if (!clientHasLogCredentials(cli)) {
-        cli->sendMsg("Permission Denied");
-        return 0;
+    uid_t uid = cli->getUid();
+    if (clientHasLogCredentials(cli)) {
+        uid = AID_ROOT;
     }
 
     if (argc < 2) {
@@ -90,7 +90,7 @@
         return 0;
     }
 
-    mBuf.clear((log_id_t) id);
+    mBuf.clear((log_id_t) id, uid);
     cli->sendMsg("success");
     return 0;
 }
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 0448afa..cd9ea20 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -232,7 +232,7 @@
 // prune "pruneRows" of type "id" from the buffer.
 //
 // mLogElementsLock must be held when this function is called.
-void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
+void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
     LogTimeEntry *oldest = NULL;
 
     LogTimeEntry::lock();
@@ -250,6 +250,38 @@
 
     LogBufferElementCollection::iterator it;
 
+    if (caller_uid != AID_ROOT) {
+        for(it = mLogElements.begin(); it != mLogElements.end();) {
+            LogBufferElement *e = *it;
+
+            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+                break;
+            }
+
+            if (e->getLogId() != id) {
+                ++it;
+                continue;
+            }
+
+            uid_t uid = e->getUid();
+
+            if (uid == caller_uid) {
+                it = mLogElements.erase(it);
+                unsigned short len = e->getMsgLen();
+                stats.subtract(len, id, uid, e->getPid());
+                delete e;
+                pruneRows--;
+                if (pruneRows == 0) {
+                    break;
+                }
+            } else {
+                ++it;
+            }
+        }
+        LogTimeEntry::unlock();
+        return;
+    }
+
     // prune by worst offender by uid
     while (pruneRows > 0) {
         // recalculate the worst offender on every batched pass
@@ -375,9 +407,9 @@
 }
 
 // clear all rows of type "id" from the buffer.
-void LogBuffer::clear(log_id_t id) {
+void LogBuffer::clear(log_id_t id, uid_t uid) {
     pthread_mutex_lock(&mLogElementsLock);
-    prune(id, ULONG_MAX);
+    prune(id, ULONG_MAX, uid);
     pthread_mutex_unlock(&mLogElementsLock);
 }
 
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index b8a54b9..4b982a8 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -23,6 +23,8 @@
 #include <sysutils/SocketClient.h>
 #include <utils/List.h>
 
+#include <private/android_filesystem_config.h>
+
 #include "LogBufferElement.h"
 #include "LogTimes.h"
 #include "LogStatistics.h"
@@ -55,7 +57,7 @@
                      bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
                      void *arg = NULL);
 
-    void clear(log_id_t id);
+    void clear(log_id_t id, uid_t uid = AID_ROOT);
     unsigned long getSize(log_id_t id);
     int setSize(log_id_t id, unsigned long size);
     unsigned long getSizeUsed(log_id_t id);
@@ -77,7 +79,7 @@
 
 private:
     void maybePrune(log_id_t id);
-    void prune(log_id_t id, unsigned long pruneRows);
+    void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
 
 };
 
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1a9a548..e7e3ec2 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -193,6 +193,7 @@
 
     if (me->skipAhead) {
         me->skipAhead--;
+        goto skip;
     }
 
     me->mStart = element->getMonotonicTime();
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 123e317..f851288 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -34,7 +34,7 @@
     -Werror \
     -fno-builtin \
 
-ifeq ($(TARGET_USES_LOGD),true)
+ifneq ($(TARGET_USES_LOGD),false)
 test_c_flags += -DTARGET_USES_LOGD=1
 endif
 
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 5b51b1f..957fdb5 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -568,10 +568,11 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
-            if (strncmp(benchmarks[i], buffer, strlen(benchmarks[i]))) {
+            char *cp = strstr(buffer, benchmarks[i]);
+            if (!cp) {
                 continue;
             }
-            sscanf(buffer, "%*s %lu %lu", &ns[i], &ns[i]);
+            sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
             fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
         }
     }
@@ -592,15 +593,15 @@
 #endif
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(25000UL, ns[log_maximum]); // 14055 user
+    EXPECT_GE(30000UL, ns[log_maximum]); // 27305 user
 #else
     EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel
 #endif
 
-    EXPECT_GE(4000UL, ns[clock_overhead]); // 2008
+    EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(250000UL, ns[log_overhead]); // 113219 user
+    EXPECT_GE(250000UL, ns[log_overhead]); // 121876 user
 #else
     EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel
 #endif
@@ -612,7 +613,7 @@
 #endif
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(20000000UL, ns[log_delay]); // 9542541 user
+    EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
 #else
     EXPECT_GE(55000UL, ns[log_delay]); // 27341 kernel
 #endif
@@ -642,36 +643,61 @@
     // 0/4225?     7454388/303656      31488/755
     //                                 ^-- benchmark_statistics_found
 
-    unsigned long nowSize = atol(benchmark_statistics_found);
+    unsigned long nowSpamSize = atol(benchmark_statistics_found);
 
     delete [] buf;
 
-    ASSERT_NE(0UL, nowSize);
+    ASSERT_NE(0UL, nowSpamSize);
 
+    // Determine if we have the spam filter enabled
     int sock = socket_local_client("logd",
                                    ANDROID_SOCKET_NAMESPACE_RESERVED,
                                    SOCK_STREAM);
+
+    ASSERT_TRUE(sock >= 0);
+
+    static const char getPruneList[] = "getPruneList";
+    if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
+        char buffer[80];
+        memset(buffer, 0, sizeof(buffer));
+        read(sock, buffer, sizeof(buffer));
+        char *cp = strchr(buffer, '\n');
+        if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
+            close(sock);
+            fprintf(stderr,
+                    "WARNING: "
+                    "Logger has SPAM filtration turned off \"%s\"\n", buffer);
+            return;
+        }
+    } else {
+        int save_errno = errno;
+        close(sock);
+        FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
+    }
+
     static const unsigned long expected_absolute_minimum_log_size = 65536UL;
     unsigned long totalSize = expected_absolute_minimum_log_size;
-    if (sock >= 0) {
-        static const char getSize[] = {
-            'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
-            LOG_ID_MAIN + '0', '\0'
-        };
-        if (write(sock, getSize, sizeof(getSize)) > 0) {
-            char buffer[80];
-            memset(buffer, 0, sizeof(buffer));
-            read(sock, buffer, sizeof(buffer));
-            totalSize = atol(buffer);
-            if (totalSize < expected_absolute_minimum_log_size) {
-                totalSize = expected_absolute_minimum_log_size;
-            }
+    static const char getSize[] = {
+        'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
+        LOG_ID_MAIN + '0', '\0'
+    };
+    if (write(sock, getSize, sizeof(getSize)) > 0) {
+        char buffer[80];
+        memset(buffer, 0, sizeof(buffer));
+        read(sock, buffer, sizeof(buffer));
+        totalSize = atol(buffer);
+        if (totalSize < expected_absolute_minimum_log_size) {
+            fprintf(stderr,
+                    "WARNING: "
+                    "Logger had unexpected referenced size \"%s\"\n", buffer);
+            totalSize = expected_absolute_minimum_log_size;
         }
-        close(sock);
     }
+    close(sock);
+
     // logd allows excursions to 110% of total size
     totalSize = (totalSize * 11 ) / 10;
 
     // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
-    ASSERT_GT(totalSize, nowSize * 2);
+    ASSERT_GT(totalSize, nowSpamSize * 2);
 }
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 2c16084..aca08bf 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -30,9 +30,17 @@
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
+# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
+bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) | $(MD5SUM)))
+bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
+$(bcp_dep) :
+	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep)
 	@echo "Generate: $< -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
 
+bcp_md5 :=
+bcp_dep :=
 #######################################
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 759380a..a176e03 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -26,29 +26,28 @@
 
     start ueventd
 
-# create mountpoints
+    # create mountpoints
     mkdir /mnt 0775 root system
 
 on init
+    sysclktz 0
 
-sysclktz 0
+    loglevel 3
 
-loglevel 3
-
-# Backward compatibility
+    # Backward compatibility
     symlink /system/etc /etc
     symlink /sys/kernel/debug /d
 
-# Right now vendor lives on the same filesystem as system,
-# but someday that may change.
+    # Right now vendor lives on the same filesystem as system,
+    # but someday that may change.
     symlink /system/vendor /vendor
 
-# Create cgroup mount point for cpu accounting
+    # Create cgroup mount point for cpu accounting
     mkdir /acct
     mount cgroup none /acct cpuacct
     mkdir /acct/uid
 
-# Create cgroup mount point for memory
+    # Create cgroup mount point for memory
     mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
     mkdir /sys/fs/cgroup/memory 0750 root system
     mount cgroup none /sys/fs/cgroup/memory memory
@@ -111,7 +110,7 @@
     # set fwmark on accepted sockets
     write /proc/sys/net/ipv4/tcp_fwmark_accept 1
 
-# Create cgroup mount points for process groups
+    # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
     chown system system /dev/cpuctl
@@ -136,21 +135,21 @@
     write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
     write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
 
-# qtaguid will limit access to specific data based on group memberships.
-#   net_bw_acct grants impersonation of socket owners.
-#   net_bw_stats grants access to other apps' detailed tagged-socket stats.
+    # qtaguid will limit access to specific data based on group memberships.
+    #   net_bw_acct grants impersonation of socket owners.
+    #   net_bw_stats grants access to other apps' detailed tagged-socket stats.
     chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
     chown root net_bw_stats /proc/net/xt_qtaguid/stats
 
-# Allow everybody to read the xt_qtaguid resource tracking misc dev.
-# This is needed by any process that uses socket tagging.
+    # Allow everybody to read the xt_qtaguid resource tracking misc dev.
+    # This is needed by any process that uses socket tagging.
     chmod 0644 /dev/xt_qtaguid
 
-# Create location for fs_mgr to store abbreviated output from filesystem
-# checker programs.
+    # Create location for fs_mgr to store abbreviated output from filesystem
+    # checker programs.
     mkdir /dev/fscklogs 0770 root system
 
-# pstore/ramoops previous console log
+    # pstore/ramoops previous console log
     mount pstore pstore /sys/fs/pstore
     chown system log /sys/fs/pstore/console-ramoops
     chmod 0440 /sys/fs/pstore/console-ramoops
@@ -237,6 +236,7 @@
     mkdir /data/misc/wifi/sockets 0770 wifi wifi
     mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
     mkdir /data/misc/dhcp 0770 dhcp dhcp
+    mkdir /data/misc/user 0771 root root
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
@@ -256,6 +256,7 @@
 
     # create dalvik-cache, so as to enforce our permissions
     mkdir /data/dalvik-cache 0771 system system
+    mkdir /data/dalvik-cache/profiles 0711 system system
 
     # create resource-cache and double-check the perms
     mkdir /data/resource-cache 0771 system system
@@ -292,17 +293,17 @@
     #setprop vold.post_fs_data_done 1
 
 on boot
-# basic network init
+    # basic network init
     ifup lo
     hostname localhost
     domainname localdomain
 
-# set RLIMIT_NICE to allow priorities from 19 to -20
+    # set RLIMIT_NICE to allow priorities from 19 to -20
     setrlimit 13 40 40
 
-# Memory management.  Basic kernel parameters, and allow the high
-# level system server to be able to adjust the kernel OOM driver
-# parameters to match how it is managing things.
+    # Memory management.  Basic kernel parameters, and allow the high
+    # level system server to be able to adjust the kernel OOM driver
+    # parameters to match how it is managing things.
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
@@ -378,8 +379,8 @@
     chown system system /sys/kernel/ipv4/tcp_rmem_max
     chown root radio /proc/cmdline
 
-# Define TCP buffer sizes for various networks
-#   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
+    # Define TCP buffer sizes for various networks
+    #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
     setprop net.tcp.buffersize.default  4096,87380,110208,4096,16384,110208
     setprop net.tcp.buffersize.wifi     524288,1048576,2097152,262144,524288,1048576
     setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
@@ -393,7 +394,7 @@
     setprop net.tcp.buffersize.gprs     4092,8760,48000,4096,8760,48000
     setprop net.tcp.buffersize.evdo     4094,87380,262144,4096,16384,262144
 
-# Define default initial receive window size in segments.
+    # Define default initial receive window size in segments.
     setprop net.tcp.default_init_rwnd 60
 
     class_start core
@@ -433,6 +434,7 @@
 # So proxy writes through init.
 on property:sys.sysctl.extra_free_kbytes=*
     write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
+
 # "tcp_default_init_rwnd" Is too long!
 on property:sys.sysctl.tcp_def_init_rwnd=*
     write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
@@ -467,7 +469,7 @@
     console
     disabled
     user shell
-    group log
+    group shell log
     seclabel u:r:shell:s0
 
 on property:ro.debuggable=1
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index fddf0a9..c53f17d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -2,73 +2,75 @@
 include $(CLEAR_VARS)
 
 TOOLS := \
-	ls \
-	mount \
 	cat \
-	ps \
-	kill \
-	ln \
-	insmod \
-	rmmod \
-	lsmod \
-	ifconfig \
-	rm \
-	mkdir \
-	rmdir \
-	getevent \
-	sendevent \
-	date \
-	wipe \
-	sync \
-	umount \
-	start \
-	stop \
-	notify \
-	cmp \
-	dmesg \
-	route \
-	hd \
-	dd \
-	df \
-	getprop \
-	setprop \
-	watchprops \
-	log \
-	sleep \
-	renice \
-	printenv \
-	smd \
+	chcon \
 	chmod \
 	chown \
-	newfs_msdos \
-	netstat \
-	ioctl \
-	mv \
-	schedtop \
-	top \
-	iftop \
+	clear \
+	cmp \
+	date \
+	dd \
+	df \
+	dmesg \
+	du \
+	getenforce \
+	getevent \
+	getprop \
+	getsebool \
+	hd \
 	id \
+	ifconfig \
+	iftop \
+	insmod \
+	ioctl \
+	ionice \
+	kill \
+	ln \
+	load_policy \
+	log \
+	ls \
+	lsmod \
+	lsof \
+	md5 \
+	mkdir \
+	mknod \
+	mkswap \
+	mount \
+	mv \
+	nandread \
+	netstat \
+	newfs_msdos \
+	nohup \
+	notify \
+	printenv \
+	ps \
+	readlink \
+	renice \
+	restorecon \
+	rm \
+	rmdir \
+	rmmod \
+	route \
+	runcon \
+	schedtop \
+	sendevent \
+	setenforce \
+	setprop \
+	setsebool \
+	sleep \
+	smd \
+	start \
+	stop \
+	swapoff \
+	swapon \
+	sync \
+	top \
+	touch \
+	umount \
 	uptime \
 	vmstat \
-	nandread \
-	ionice \
-	touch \
-	lsof \
-	du \
-	md5 \
-	clear \
-	getenforce \
-	setenforce \
-	chcon \
-	restorecon \
-	runcon \
-	getsebool \
-	setsebool \
-	load_policy \
-	swapon \
-	swapoff \
-	mkswap \
-	readlink
+	watchprops \
+	wipe \
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TOOLS += r
@@ -92,21 +94,25 @@
 	toolbox.c \
 	uid_from_user.c \
 
-LOCAL_C_INCLUDES := bionic/libc/bionic
-
 LOCAL_CFLAGS += \
     -std=gnu99 \
     -Werror -Wno-unused-parameter \
     -include bsd-compatibility.h \
 
+LOCAL_C_INCLUDES += external/openssl/include
+
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	liblog \
-	libc \
-	libusbhost \
-	libselinux
+    libcrypto \
+    libcutils \
+    libselinux \
+
+# libusbhost is only used by lsusb, and that isn't usually included in toolbox.
+# The linker strips out all the unused library code in the normal case.
+LOCAL_STATIC_LIBRARIES := \
+    libusbhost \
 
 LOCAL_MODULE := toolbox
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 # Including this will define $(intermediates).
 #
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index c2256ff..da83ec3 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -295,6 +295,7 @@
 {
     int version;
     int fd;
+    int clkid = CLOCK_MONOTONIC;
     struct pollfd *new_ufds;
     char **new_device_names;
     char name[80];
@@ -335,6 +336,11 @@
         idstr[0] = '\0';
     }
 
+    if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
+        fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
+        // a non-fatal error
+    }
+
     new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
     if(new_ufds == NULL) {
         fprintf(stderr, "out of memory\n");
@@ -470,9 +476,9 @@
     return 0;
 }
 
-static void usage(int argc, char *argv[])
+static void usage(char *name)
 {
-    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
+    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
     fprintf(stderr, "    -t: show time stamps\n");
     fprintf(stderr, "    -n: don't print newlines\n");
     fprintf(stderr, "    -s: print switch states for given bits\n");
@@ -568,7 +574,7 @@
             fprintf(stderr, "%s: invalid option -%c\n",
                 argv[0], optopt);
         case 'h':
-            usage(argc, argv);
+            usage(argv[0]);
             exit(1);
         }
     } while (1);
@@ -580,7 +586,7 @@
         optind++;
     }
     if (optind != argc) {
-        usage(argc, argv);
+        usage(argv[0]);
         exit(1);
     }
     nfds = 1;
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index 80c0e5c..b953176 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -61,11 +61,11 @@
 {
     struct ifreq ifr;
     int s;
-    unsigned int addr, mask, flags;
+    unsigned int flags;
     char astring[20];
     char mstring[20];
     char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
-    
+
     argc--;
     argv++;
 
@@ -85,13 +85,17 @@
             perror(ifr.ifr_name);
             return -1;
         } else
-            addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+            strlcpy(astring,
+                   inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+                   sizeof(astring));
 
         if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
             perror(ifr.ifr_name);
             return -1;
         } else
-            mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+            strlcpy(mstring,
+                   inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+                   sizeof(mstring));
 
         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
             perror(ifr.ifr_name);
@@ -99,16 +103,6 @@
         } else
             flags = ifr.ifr_flags;
 
-        sprintf(astring, "%d.%d.%d.%d",
-                addr & 0xff,
-                ((addr >> 8) & 0xff),
-                ((addr >> 16) & 0xff),
-                ((addr >> 24) & 0xff));
-        sprintf(mstring, "%d.%d.%d.%d",
-                mask & 0xff,
-                ((mask >> 8) & 0xff),
-                ((mask >> 16) & 0xff),
-                ((mask >> 24) & 0xff));
         printf("%s: ip %s mask %s flags [", ifr.ifr_name,
                astring,
                mstring
diff --git a/toolbox/md5.c b/toolbox/md5.c
index 2fb8b05..5de4d9e 100644
--- a/toolbox/md5.c
+++ b/toolbox/md5.c
@@ -4,12 +4,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <md5.h>
-
-/* When this was written, bionic's md5.h did not define this. */
-#ifndef MD5_DIGEST_LENGTH
-#define MD5_DIGEST_LENGTH 16
-#endif
+#include <openssl/md5.h>
 
 static int usage()
 {
@@ -30,7 +25,6 @@
         return -1;
     }
 
-    /* Note that bionic's MD5_* functions return void. */
     MD5_Init(&md5_ctx);
 
     while (1) {
diff --git a/toolbox/mknod.c b/toolbox/mknod.c
new file mode 100644
index 0000000..0fedece
--- /dev/null
+++ b/toolbox/mknod.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int print_usage() {
+    fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n");
+    return EXIT_FAILURE;
+}
+
+int mknod_main(int argc, char **argv) {
+    char *path = NULL;
+    int major = 0;
+    int minor = 0;
+    int args = 0;
+    mode_t mode = 0660;
+
+    /* Check correct argument count is 3 or 5 */
+    if (argc != 3 && argc != 5) {
+        fprintf(stderr, "Incorrect argument count\n");
+        return print_usage();
+    }
+
+    path = argv[1];
+
+    const char node_type = *argv[2];
+    switch (node_type) {
+    case 'b':
+        mode |= S_IFBLK;
+        args = 5;
+        break;
+    case 'c':
+    case 'u':
+        mode |= S_IFCHR;
+        args = 5;
+        break;
+    case 'p':
+        mode |= S_IFIFO;
+        args = 3;
+        break;
+    default:
+        fprintf(stderr, "Invalid node type '%c'\n", node_type);
+        return print_usage();
+    }
+
+    if (argc != args) {
+        if (args == 5) {
+            fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type);
+        } else {
+            fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type);
+        }
+        return print_usage();
+    }
+
+    if (args == 5) {
+        major = atoi(argv[3]);
+        minor = atoi(argv[4]);
+    }
+
+    if (mknod(path, mode, makedev(major, minor))) {
+        perror("Unable to create node");
+        return EXIT_FAILURE;
+    }
+    return 0;
+}
diff --git a/toolbox/nohup.c b/toolbox/nohup.c
new file mode 100644
index 0000000..363999d
--- /dev/null
+++ b/toolbox/nohup.c
@@ -0,0 +1,26 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int nohup_main(int argc, char *argv[])
+{
+    if (argc < 2) {
+        fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]);
+        return EXIT_FAILURE;
+    }
+    signal(SIGHUP, SIG_IGN);
+    argv++;
+    if (strcmp(argv[0], "-n") == 0) {
+        argv++;
+        signal(SIGINT, SIG_IGN);
+        signal(SIGSTOP, SIG_IGN);
+        signal(SIGTTIN, SIG_IGN);
+        signal(SIGTTOU, SIG_IGN);
+        signal(SIGQUIT, SIG_IGN);
+        signal(SIGTERM, SIG_IGN);
+    }
+    execvp(argv[0], argv);
+    perror(argv[0]);
+    return EXIT_FAILURE;
+}