Merge "property_service: get rid of hard coded property / control list"
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/usb_vendors.c b/adb/usb_vendors.c
index 705f02b..957e5db 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -84,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
@@ -160,6 +162,8 @@
 #define VENDOR_ID_SHARP         0x04dd
 // SK Telesys's USB Vendor ID
 #define VENDOR_ID_SK_TELESYS    0x1F53
+// Smartisan's USB Vendor ID
+#define VENDOR_ID_SMARTISAN     0x29a9
 // Sony's USB Vendor ID
 #define VENDOR_ID_SONY          0x054C
 // Sony Ericsson's USB Vendor ID
@@ -217,6 +221,7 @@
     VENDOR_ID_HAIER,
     VENDOR_ID_HARRIS,
     VENDOR_ID_HISENSE,
+    VENDOR_ID_HONEYWELL,
     VENDOR_ID_HP,
     VENDOR_ID_HTC,
     VENDOR_ID_HUAWEI,
@@ -255,6 +260,7 @@
     VENDOR_ID_SAMSUNG,
     VENDOR_ID_SHARP,
     VENDOR_ID_SK_TELESYS,
+    VENDOR_ID_SMARTISAN,
     VENDOR_ID_SONY,
     VENDOR_ID_SONY_ERICSSON,
     VENDOR_ID_T_AND_A,
diff --git a/charger/charger.c b/charger/charger.c
index e3cadb1..15add87 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -40,6 +40,7 @@
 #include <cutils/list.h>
 #include <cutils/misc.h>
 #include <cutils/uevent.h>
+#include <cutils/properties.h>
 
 #ifdef CHARGER_ENABLE_SUSPEND
 #include <suspend/autosuspend.h>
@@ -830,8 +831,16 @@
         if (key->down) {
             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
             if (now >= reboot_timeout) {
-                LOGI("[%lld] rebooting\n", now);
-                android_reboot(ANDROID_RB_RESTART, 0, 0);
+                /* We do not currently support booting from charger mode on
+                   all devices. Check the property and continue booting or reboot
+                   accordingly. */
+                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
+                    LOGI("[%lld] booting from charger mode\n", now);
+                    property_set("sys.boot_from_charger_mode", "1");
+                } else {
+                    LOGI("[%lld] rebooting\n", now);
+                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                }
             } else {
                 /* if the key is pressed but timeout hasn't expired,
                  * make sure we wake up at the right-ish time to check
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index f3409d5..48308c3 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -44,7 +44,7 @@
     io.iov_len = sizeof(regs);
 
     if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
-        LOG_ERROR("%s: ptrace failed to get registers: %s\n",
+        _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
              __func__, strerror(errno));
         return;
     }
@@ -80,7 +80,7 @@
   io.iov_len = sizeof(r);
 
   if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
-    LOG_ERROR("ptrace error: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
     return;
   }
 
@@ -105,7 +105,7 @@
   io.iov_len = sizeof(f);
 
   if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
-    LOG_ERROR("ptrace error: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index d08242e..c4a2143 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -49,8 +49,9 @@
   struct tm tm;
   localtime_r(&t, &tm);
   char timestr[64];
+  _LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING);
   strftime(timestr, sizeof(timestr), "%F %T", &tm);
-  _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
+  _LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr);
 
   if (procname) {
     _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
@@ -95,7 +96,7 @@
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
-    LOG_ERROR("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;
   }
 }
@@ -105,7 +106,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);
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index dde8f90..fc13977 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -61,34 +61,24 @@
   char exe[PATH_MAX];
   int count;
   if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
-    LOG_ERROR("readlink('%s') failed: %s", path, strerror(errno));
+    ALOGE("readlink('%s') failed: %s", path, strerror(errno));
     strlcpy(exe, "unknown", sizeof(exe));
   } else {
     exe[count] = '\0';
   }
 
-  // Turn "/system/bin/app_process" into "app_process".
-  // gdbserver doesn't cope with full paths (though we should fix that
-  // and remove this).
-  char* name = strrchr(exe, '/');
-  if (name == NULL) {
-    name = exe; // No '/' found.
-  } else {
-    ++name; // Skip the '/'.
-  }
-
   // Explain how to attach the debugger.
-  LOG_ERROR(    "********************************************************\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, exe, pid);
 
   // Wait for VOLUME DOWN.
   if (init_getevent() == 0) {
@@ -103,7 +93,7 @@
     uninit_getevent();
   }
 
-  LOG_ERROR("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) {
@@ -139,11 +129,11 @@
   socklen_t len = sizeof(cr);
   int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
   if (status != 0) {
-    LOG_ERROR("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];
@@ -152,7 +142,7 @@
   pollfds[0].revents = 0;
   status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
   if (status != 1) {
-    LOG_ERROR("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;
   }
 
@@ -160,14 +150,11 @@
   memset(&msg, 0, sizeof(msg));
   status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
   if (status < 0) {
-    LOG_ERROR("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_ERROR("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;
   }
 
@@ -185,7 +172,7 @@
     struct stat s;
     snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
     if (stat(buf, &s)) {
-      LOG_ERROR("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;
     }
@@ -196,7 +183,7 @@
     status = get_process_info(out_request->tid, &out_request->pid,
                               &out_request->uid, &out_request->gid);
     if (status < 0) {
-      LOG_ERROR("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 {
@@ -217,13 +204,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
@@ -237,12 +224,12 @@
     // See details in bionic/libc/linker/debugger.c, in function
     // debugger_signal_handler().
     if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
-      LOG_ERROR("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_ERROR("failed responding to client: %s\n", strerror(errno));
+        ALOGE("failed responding to client: %s\n", strerror(errno));
       } else {
         char* tombstone_path = NULL;
 
@@ -261,20 +248,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_ERROR("ptrace continue failed: %s\n", strerror(errno));
+                  ALOGE("ptrace continue failed: %s\n", strerror(errno));
                 }
                 continue; // loop again
               }
@@ -290,7 +277,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:
@@ -300,13 +287,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_ERROR("process stopped due to unexpected signal %d\n", signal);
+              ALOGE("process stopped due to unexpected signal %d\n", signal);
               break;
           }
           break;
@@ -322,14 +308,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_ERROR("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;
         }
 
@@ -341,7 +327,7 @@
       } else {
         // just detach
         if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-          LOG_ERROR("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;
         }
       }
@@ -353,7 +339,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_ERROR("debuggerd committing suicide to free the zombie!\n");
+        ALOGE("debuggerd committing suicide to free the zombie!\n");
         kill(getpid(), SIGKILL);
       }
     }
@@ -399,16 +385,16 @@
     return 1;
   fcntl(s, F_SETFD, FD_CLOEXEC);
 
-  LOG_ERROR("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/mips/machine.cpp b/debuggerd/mips/machine.cpp
index 605275b..97834c7 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -87,7 +87,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   pt_regs_mips_t r;
   if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    LOG_ERROR("cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 37839aa..a58d9e5 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -58,21 +58,6 @@
 // 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:
@@ -235,7 +220,7 @@
     fclose(fp);
   }
 
-  _LOG(log, logtype::THREAD, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
+  _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
        threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
 }
 
@@ -343,8 +328,9 @@
   }
 }
 
-static void dump_map(log_t* log, const backtrace_map_t* map) {
-  _LOG(log, logtype::MAPS, "    %" 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());
 }
@@ -366,10 +352,18 @@
     return;
   }
 
-  _LOG(log, logtype::MAPS, "\nmemory map:\n");
+  _LOG(log, logtype::MAPS, "\nmemory map: (fault address prefixed with --->)\n");
 
+  bool found_map = false;
   for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    dump_map(log, &*it);
+    bool in_map = addr >= (*it).start && addr < (*it).end;
+    dump_map(log, &*it, in_map);
+    if(in_map) {
+      found_map = true;
+    }
+  }
+  if(!found_map) {
+    _LOG(log, logtype::ERROR, "\nFault address was not in any map!");
   }
 }
 
@@ -395,7 +389,7 @@
   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;
   }
 
@@ -416,15 +410,14 @@
 
     // Skip this thread if cannot ptrace it
     if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
-      LOG_ERROR("ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
+      _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
       continue;
     }
 
+    log->current_tid = new_tid;
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
     dump_thread_info(log, pid, new_tid);
 
-    log->current_tid = new_tid;
-
     UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
     if (backtrace->Unwind(0)) {
       dump_thread(backtrace.get(), log, total_sleep_time_usec);
@@ -433,7 +426,7 @@
     log->current_tid = log->crashed_tid;
 
     if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
-      LOG_ERROR("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;
     }
   }
@@ -457,7 +450,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;
   }
 
@@ -474,17 +467,17 @@
         // non-blocking EOF; we're done
         break;
       } else {
-        LOG_ERROR("Error while reading log: %s\n",
+        _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
           strerror(-actual));
         break;
       }
     } else if (actual == 0) {
-      LOG_ERROR("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.
@@ -690,7 +683,7 @@
   }
 
   if (oldest < 0) {
-    LOG_ERROR("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;
   }
 
@@ -698,7 +691,7 @@
   snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
   *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
   if (*fd < 0) {
-    LOG_ERROR("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);
@@ -736,7 +729,7 @@
 }
 
 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;
@@ -744,11 +737,11 @@
   log.crashed_tid = tid;
 
   if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
-    LOG_ERROR("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_ERROR("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;
@@ -756,11 +749,11 @@
   if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
     path = find_and_open_tombstone(&fd);
   } else {
-    LOG_ERROR("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_ERROR("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;
   }
@@ -770,7 +763,6 @@
   // 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);
 
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 f0d9220..a163344 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -37,7 +37,7 @@
     int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
     if (written < 0) {
       // hard failure
-      LOG_ERROR("AM write failure (%d / %s)\n", errno, strerror(errno));
+      ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
       return -1;
     }
     to_write -= written;
@@ -57,12 +57,10 @@
 }
 
 void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
-  bool write_to_tombstone = log && log->tfd;
-  bool write_to_logcat = (!log || !log->quiet) && is_allowed_in_logcat(ltype);
-  if (log != NULL) {
-    write_to_logcat &= (log->crashed_tid == log->current_tid);
-  }
-  bool write_to_activitymanager = log && log->amfd >= 0 && is_allowed_in_logcat(ltype);
+  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;
@@ -98,25 +96,25 @@
     if (n < 0) {
       if (errno == EAGAIN)
         continue;
-      LOG_ERROR("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_ERROR("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_ERROR("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;
   }
@@ -126,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_ERROR("timed out waiting for tid=%d to stop\n", tid);
+      ALOGE("timed out waiting for tid=%d to stop\n", tid);
       break;
     }
 
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index fdfb2ec..f2e2d29 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,13 +21,27 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__)
+#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
+
+
 typedef struct {
     /* tombstone file descriptor */
     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.
@@ -51,10 +65,6 @@
 void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-/* Further helpful macros */
-#define LOG_ERROR(fmt...) _LOG(NULL, logtype::ERROR, fmt)
-#define XLOG(fmt...) do {} while(0)
-
 int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
 void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
 
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 2d553fa..57330c1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -31,7 +31,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   struct pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-    LOG_ERROR("cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
   _LOG(log, logtype::REGISTERS, "    eax %08lx  ebx %08lx  ecx %08lx  edx %08lx\n",
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index 6cb0e8d..af4f35a 100755
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -33,7 +33,7 @@
 void dump_registers(log_t* log, pid_t tid) {
     struct user_regs_struct r;
     if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-        LOG_ERROR("cannot get registers: %s\n", strerror(errno));
+        _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
         return;
     }
     _LOG(log, logtype::REGISTERS, "    rax %016lx  rbx %016lx  rcx %016lx  rdx %016lx\n",
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 9c04c21..266d0b5 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -1216,6 +1216,7 @@
     }
     if (wants_reboot) {
         fb_queue_reboot();
+        fb_queue_wait_for_disconnect();
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
         fb_queue_wait_for_disconnect();
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/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 4f90ef1..007a905 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -51,6 +51,8 @@
 #include <cutils/atomic-x86.h>
 #elif defined(__x86_64__)
 #include <cutils/atomic-x86_64.h>
+#elif defined(__mips64)
+#include <cutils/atomic-mips64.h>
 #elif defined(__mips__)
 #include <cutils/atomic-mips.h>
 #else
diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h
index f9d3e25..1ed833d 100644
--- a/include/cutils/atomic-mips.h
+++ b/include/cutils/atomic-mips.h
@@ -117,23 +117,6 @@
 
 
 extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_swap(int32_t new_value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-    __asm__ __volatile__ (
-        "    move %[status], %[new_value]\n"
-        "    ll %[prev], (%[ptr])\n"
-        "    sc %[status], (%[ptr])\n"
-        : [prev] "=&r" (prev), [status] "=&r" (status)
-        : [ptr] "r" (ptr), [new_value] "r" (new_value)
-        );
-    } while (__builtin_expect(status == 0, 0));
-    android_memory_barrier();
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
 android_atomic_add(int32_t increment, volatile int32_t *ptr)
 {
     int32_t prev, status;
diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h
new file mode 100644
index 0000000..99bbe3a
--- /dev/null
+++ b/include/cutils/atomic-mips64.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_MIPS64_H
+#define ANDROID_CUTILS_ATOMIC_MIPS64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+{
+    __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+{
+    android_compiler_barrier();
+}
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+{
+    android_compiler_barrier();
+}
+#else
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+{
+    __asm__ __volatile__ ("sync" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+{
+    __asm__ __volatile__ ("sync" : : : "memory");
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+    int32_t value = *ptr;
+    android_memory_barrier();
+    return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+    int64_t value = *ptr;
+    android_memory_barrier();
+    return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+    android_memory_barrier();
+    return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+    android_memory_barrier();
+    return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+{
+    *ptr = value;
+    android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+    *ptr = value;
+    android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+    android_memory_barrier();
+    *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+    android_memory_barrier();
+    *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    do {
+        __asm__ __volatile__ (
+            "    ll     %[prev], (%[ptr])\n"
+            "    li     %[status], 1\n"
+            "    bne    %[prev], %[old], 9f\n"
+            "    move   %[status], %[new_value]\n"
+            "    sc     %[status], (%[ptr])\n"
+            "9:\n"
+            : [prev] "=&r" (prev), [status] "=&r" (status)
+            : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value)
+            );
+    } while (__builtin_expect(status == 0, 0));
+    return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+                             volatile int64_t *ptr)
+{
+    return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value,
+                           int32_t new_value,
+                           volatile int32_t *ptr)
+{
+    int status = android_atomic_cas(old_value, new_value, ptr);
+    android_memory_barrier();
+    return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+                                     volatile int64_t *ptr)
+{
+    int status = android_atomic_cas64(old_value, new_value, ptr);
+    android_memory_barrier();
+    return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value,
+                           int32_t new_value,
+                           volatile int32_t *ptr)
+{
+    android_memory_barrier();
+    return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+                                     volatile int64_t *ptr)
+{
+    android_memory_barrier();
+    return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    android_memory_barrier();
+    do {
+        __asm__ __volatile__ (
+        "    ll    %[prev], (%[ptr])\n"
+        "    addu  %[status], %[prev], %[inc]\n"
+        "    sc    %[status], (%[ptr])\n"
+        :  [status] "=&r" (status), [prev] "=&r" (prev)
+        :  [ptr] "r" (ptr), [inc] "Ir" (increment)
+        );
+    } while (__builtin_expect(status == 0, 0));
+    return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_inc(volatile int32_t *addr)
+{
+    return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_dec(volatile int32_t *addr)
+{
+    return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    android_memory_barrier();
+    do {
+        __asm__ __volatile__ (
+        "    ll    %[prev], (%[ptr])\n"
+        "    and   %[status], %[prev], %[value]\n"
+        "    sc    %[status], (%[ptr])\n"
+        : [prev] "=&r" (prev), [status] "=&r" (status)
+        : [ptr] "r" (ptr), [value] "Ir" (value)
+            );
+    } while (__builtin_expect(status == 0, 0));
+    return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+    int32_t prev, status;
+    android_memory_barrier();
+    do {
+        __asm__ __volatile__ (
+        "    ll    %[prev], (%[ptr])\n"
+        "    or    %[status], %[prev], %[value]\n"
+        "    sc    %[status], (%[ptr])\n"
+        : [prev] "=&r" (prev), [status] "=&r" (status)
+        : [ptr] "r" (ptr), [value] "Ir" (value)
+            );
+    } while (__builtin_expect(status == 0, 0));
+    return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */
diff --git a/include/cutils/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/init/builtins.c b/init/builtins.c
index d9f7bbe..0c32b2a 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -877,6 +877,14 @@
     return -1;
 }
 
+int do_load_all_props(int nargs, char **args) {
+    if (nargs == 1) {
+        load_all_props();
+        return 0;
+    }
+    return -1;
+}
+
 int do_wait(int nargs, char **args)
 {
     if (nargs == 2) {
diff --git a/init/devices.c b/init/devices.c
index 02698ef..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;
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 c79929b..f001071 100644
--- a/init/init.c
+++ b/init/init.c
@@ -938,7 +938,7 @@
     return 0;
 }
 
-static int log_callback(int type, const char *fmt, ...)
+int log_callback(int type, const char *fmt, ...)
 {
     int level;
     va_list ap;
@@ -1051,8 +1051,7 @@
     is_charger = !strcmp(bootmode, "charger");
 
     INFO("property init\n");
-    if (!is_charger)
-        property_load_boot_defaults();
+    property_load_boot_defaults();
 
     INFO("reading config file\n");
     init_parse_config_file("/init.rc");
@@ -1067,28 +1066,19 @@
     /* execute all the boot actions to get us started */
     action_for_each_trigger("init", action_add_queue_tail);
 
-    /* skip mounting filesystems in charger mode */
-    if (!is_charger) {
-        action_for_each_trigger("early-fs", action_add_queue_tail);
-        action_for_each_trigger("fs", action_add_queue_tail);
-        action_for_each_trigger("post-fs", action_add_queue_tail);
-        action_for_each_trigger("post-fs-data", action_add_queue_tail);
-    }
-
     /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
      * wasn't ready immediately after wait_for_coldboot_done
      */
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-
     queue_builtin_action(property_service_init_action, "property_service_init");
     queue_builtin_action(signal_init_action, "signal_init");
     queue_builtin_action(check_startup_action, "check_startup");
 
+    /* Don't mount filesystems or start core system services if in charger mode. */
     if (is_charger) {
         action_for_each_trigger("charger", action_add_queue_tail);
     } else {
-        action_for_each_trigger("early-boot", action_add_queue_tail);
-        action_for_each_trigger("boot", action_add_queue_tail);
+        action_for_each_trigger("late-init", action_add_queue_tail);
     }
 
         /* run all property triggers based on current state of the properties */
diff --git a/init/init_parser.c b/init/init_parser.c
index 7800082..289e759 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -120,6 +120,7 @@
     case 'l':
         if (!strcmp(s, "oglevel")) return K_loglevel;
         if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
+        if (!strcmp(s, "oad_all_props")) return K_load_all_props;
         break;
     case 'm':
         if (!strcmp(s, "kdir")) return K_mkdir;
diff --git a/init/keywords.h b/init/keywords.h
index 6625330..2d97e5b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -39,6 +39,7 @@
 int do_chmod(int nargs, char **args);
 int do_loglevel(int nargs, char **args);
 int do_load_persist_props(int nargs, char **args);
+int do_load_all_props(int nargs, char **args);
 int do_wait(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -101,6 +102,7 @@
     KEYWORD(chmod,       COMMAND, 2, do_chmod)
     KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
     KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
+    KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
     KEYWORD(ioprio,      OPTION,  0, 0)
 #ifdef __MAKE_KEYWORD_ENUM__
     KEYWORD_COUNT,
diff --git a/init/log.h b/init/log.h
index 0ba770f..e9cb65a 100644
--- a/init/log.h
+++ b/init/log.h
@@ -23,4 +23,6 @@
 #define NOTICE(x...)  KLOG_NOTICE("init", x)
 #define INFO(x...)    KLOG_INFO("init", x)
 
+extern int log_callback(int type, const char *fmt, ...);
+
 #endif
diff --git a/init/property_service.c b/init/property_service.c
index aaf6c1e..d112699 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -520,10 +520,8 @@
     load_persistent_properties();
 }
 
-void start_property_service(void)
+void load_all_props(void)
 {
-    int fd;
-
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
     load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
     load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
@@ -532,6 +530,11 @@
 
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
+}
+
+void start_property_service(void)
+{
+    int fd;
 
     fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
     if(fd < 0) return;
diff --git a/init/property_service.h b/init/property_service.h
index 46cbd8f..730495e 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -24,6 +24,7 @@
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
+extern void load_all_props(void);
 extern void start_property_service(void);
 void get_property_workspace(int *fd, int *sz);
 extern int __property_get(const char *name, char *value);
diff --git a/init/ueventd.c b/init/ueventd.c
index 662196d..833e4fd 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <signal.h>
+#include <selinux/selinux.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -76,6 +77,10 @@
     }
 #endif
 
+    union selinux_callback cb;
+    cb.func_log = log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+
     INFO("starting ueventd\n");
 
     /* Respect hardware passed in through the kernel cmd line. Here we will look
@@ -122,6 +127,7 @@
     uid_t uid;
     gid_t gid;
     int prefix = 0;
+    int wildcard = 0;
     char *endptr;
     int ret;
     char *tmp = 0;
@@ -154,9 +160,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 +193,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.mk b/libbacktrace/Android.mk
index 1de81e7..c321369 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -201,6 +201,8 @@
 LOCAL_SRC_FILES := \
 	BacktraceMap.cpp \
 
+LOCAL_MULTILIB := both
+
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 endif # TARGET_BUILD_APPS
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index c0faed4..933a77b 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -134,6 +134,9 @@
 LOCAL_SRC_FILES_arm += \
         arch-arm/memset32.S \
 
+LOCAL_SRC_FILES_arm64 += \
+        arch-arm64/android_memset.S \
+
 LOCAL_SRC_FILES_mips += \
         arch-mips/android_memset.c \
 
@@ -146,6 +149,7 @@
         arch-x86_64/android_memset32_SSE2-atom.S \
 
 LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 4697265..6efab9f 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -51,8 +51,10 @@
 
 android_memset32:
         .fnstart
-        .save       {lr}
+        .cfi_startproc
         str         lr, [sp, #-4]!
+        .cfi_def_cfa_offset 4
+        .cfi_rel_offset lr, 0
 
         /* align the destination to a cache-line */
         mov         r12, r1
@@ -89,5 +91,8 @@
         strmih      lr, [r0], #2
 
         ldr         lr, [sp], #4
+        .cfi_def_cfa_offset 0
+        .cfi_restore lr
         bx          lr
+        .cfi_endproc
         .fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
new file mode 100644
index 0000000..9a83a68
--- /dev/null
+++ b/libcutils/arch-arm64/android_memset.S
@@ -0,0 +1,211 @@
+/* Copyright (c) 2012, Linaro Limited
+   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 the Linaro 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
+   HOLDER 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.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ * Unaligned accesses
+ *
+ */
+
+/* By default we assume that the DC instruction can be used to zero
+   data blocks more efficiently.  In some circumstances this might be
+   unsafe, for example in an asymmetric multiprocessor environment with
+   different DC clear lengths (neither the upper nor lower lengths are
+   safe to use). */
+
+#define dst  		x0
+#define count		x2
+#define tmp1		x3
+#define tmp1w		w3
+#define tmp2		x4
+#define tmp2w		w4
+#define zva_len_x	x5
+#define zva_len		w5
+#define zva_bits_x	x6
+
+#define A_l		x1
+#define A_lw		w1
+#define tmp3w		w9
+
+#define ENTRY(f) \
+  .text; \
+  .globl f; \
+  .align 0; \
+  .type f, %function; \
+  f: \
+  .cfi_startproc \
+
+#define END(f) \
+  .cfi_endproc; \
+  .size f, .-f; \
+
+ENTRY(android_memset16)
+	ands   A_lw, A_lw, #0xffff
+	b.eq	.Lzero_mem
+	orr	A_lw, A_lw, A_lw, lsl #16
+	b .Lexpand_to_64
+END(android_memset16)
+
+ENTRY(android_memset32)
+	cmp	    A_lw, #0
+	b.eq	.Lzero_mem
+.Lexpand_to_64:
+	orr	A_l, A_l, A_l, lsl #32
+.Ltail_maybe_long:
+	cmp	count, #64
+	b.ge	.Lnot_short
+.Ltail_maybe_tiny:
+	cmp	count, #15
+	b.le	.Ltail15tiny
+.Ltail63:
+	ands	tmp1, count, #0x30
+	b.eq	.Ltail15
+	add	dst, dst, tmp1
+	cmp	tmp1w, #0x20
+	b.eq	1f
+	b.lt	2f
+	stp	A_l, A_l, [dst, #-48]
+1:
+	stp	A_l, A_l, [dst, #-32]
+2:
+	stp	A_l, A_l, [dst, #-16]
+
+.Ltail15:
+	and	count, count, #15
+	add	dst, dst, count
+	stp	A_l, A_l, [dst, #-16]	/* Repeat some/all of last store. */
+	ret
+
+.Ltail15tiny:
+	/* Set up to 15 bytes.  Does not assume earlier memory
+	   being set.  */
+	tbz	count, #3, 1f
+	str	A_l, [dst], #8
+1:
+	tbz	count, #2, 1f
+	str	A_lw, [dst], #4
+1:
+	tbz	count, #1, 1f
+	strh	A_lw, [dst], #2
+1:
+	ret
+
+	/* Critical loop.  Start at a new cache line boundary.  Assuming
+	 * 64 bytes per line, this ensures the entire loop is in one line.  */
+	.p2align 6
+.Lnot_short:
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	2f
+	/* Bring DST to 128-bit (16-byte) alignment.  We know that there's
+	 * more than that to set, so we simply store 16 bytes and advance by
+	 * the amount required to reach alignment.  */
+	sub	count, count, tmp2
+	stp	A_l, A_l, [dst]
+	add	dst, dst, tmp2
+	/* There may be less than 63 bytes to go now.  */
+	cmp	count, #63
+	b.le	.Ltail63
+2:
+	sub	dst, dst, #16		/* Pre-bias.  */
+	sub	count, count, #64
+1:
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	stp	A_l, A_l, [dst, #48]
+	stp	A_l, A_l, [dst, #64]!
+	subs	count, count, #64
+	b.ge	1b
+	tst	count, #0x3f
+	add	dst, dst, #16
+	b.ne	.Ltail63
+	ret
+
+	/* For zeroing memory, check to see if we can use the ZVA feature to
+	 * zero entire 'cache' lines.  */
+.Lzero_mem:
+	mov	A_l, #0
+	cmp	count, #63
+	b.le	.Ltail_maybe_tiny
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	1f
+	sub	count, count, tmp2
+	stp	A_l, A_l, [dst]
+	add	dst, dst, tmp2
+	cmp	count, #63
+	b.le	.Ltail63
+1:
+	/* For zeroing small amounts of memory, it's not worth setting up
+	 * the line-clear code.  */
+	cmp	count, #128
+	b.lt	.Lnot_short
+	mrs	tmp1, dczid_el0
+	tbnz	tmp1, #4, .Lnot_short
+	mov	tmp3w, #4
+	and	zva_len, tmp1w, #15	/* Safety: other bits reserved.  */
+	lsl	zva_len, tmp3w, zva_len
+
+.Lzero_by_line:
+	/* Compute how far we need to go to become suitably aligned.  We're
+	 * already at quad-word alignment.  */
+	cmp	count, zva_len_x
+	b.lt	.Lnot_short		/* Not enough to reach alignment.  */
+	sub	zva_bits_x, zva_len_x, #1
+	neg	tmp2, dst
+	ands	tmp2, tmp2, zva_bits_x
+	b.eq	1f			/* Already aligned.  */
+	/* Not aligned, check that there's enough to copy after alignment.  */
+	sub	tmp1, count, tmp2
+	cmp	tmp1, #64
+	ccmp	tmp1, zva_len_x, #8, ge	/* NZCV=0b1000 */
+	b.lt	.Lnot_short
+	/* We know that there's at least 64 bytes to zero and that it's safe
+	 * to overrun by 64 bytes.  */
+	mov	count, tmp1
+2:
+	stp	A_l, A_l, [dst]
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	subs	tmp2, tmp2, #64
+	stp	A_l, A_l, [dst, #48]
+	add	dst, dst, #64
+	b.ge	2b
+	/* We've overrun a bit, so adjust dst downwards.  */
+	add	dst, dst, tmp2
+1:
+	sub	count, count, zva_len_x
+3:
+	dc	zva, dst
+	add	dst, dst, zva_len_x
+	subs	count, count, zva_len_x
+	b.ge	3b
+	ands	count, count, zva_bits_x
+	b.ne	.Ltail_maybe_long
+	ret
+END(android_memset32)
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..8e65310
--- /dev/null
+++ b/libcutils/tests/Android.mk
@@ -0,0 +1,48 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+test_src_files := \
+    MemsetTest.cpp \
+    PropertiesTest.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    liblog \
+    libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES := \
+    libc \
+    libcutils \
+    liblog \
+    libstlport_static \
+    libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/tests/MemsetTest.cpp
new file mode 100644
index 0000000..45efc51
--- /dev/null
+++ b/libcutils/tests/MemsetTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <gtest/gtest.h>
+
+#define FENCEPOST_LENGTH 8
+
+#define MAX_TEST_SIZE (64*1024)
+// Choose values that have no repeating byte values.
+#define MEMSET16_PATTERN 0xb139
+#define MEMSET32_PATTERN 0x48193a27
+
+enum test_e {
+  MEMSET16 = 0,
+  MEMSET32,
+};
+
+static int g_memset16_aligns[][2] = {
+  { 2, 0 },
+  { 4, 0 },
+  { 8, 0 },
+  { 16, 0 },
+  { 32, 0 },
+  { 64, 0 },
+  { 128, 0 },
+
+  { 4, 2 },
+
+  { 8, 2 },
+  { 8, 4 },
+  { 8, 6 },
+
+  { 128, 2 },
+  { 128, 4 },
+  { 128, 6 },
+  { 128, 8 },
+  { 128, 10 },
+  { 128, 12 },
+  { 128, 14 },
+  { 128, 16 },
+};
+
+static int g_memset32_aligns[][2] = {
+  { 4, 0 },
+  { 8, 0 },
+  { 16, 0 },
+  { 32, 0 },
+  { 64, 0 },
+  { 128, 0 },
+
+  { 8, 4 },
+
+  { 128, 4 },
+  { 128, 8 },
+  { 128, 12 },
+  { 128, 16 },
+};
+
+static size_t GetIncrement(size_t len, size_t min_incr) {
+  if (len >= 4096) {
+    return 1024;
+  } else if (len >= 1024) {
+    return 256;
+  }
+  return min_incr;
+}
+
+// Return a pointer into the current buffer with the specified alignment.
+static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
+  uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
+  if (alignment > 0) {
+      // When setting the alignment, set it to exactly the alignment chosen.
+      // The pointer returned will be guaranteed not to be aligned to anything
+      // more than that.
+      ptr += alignment - (ptr & (alignment - 1));
+      ptr |= alignment | or_mask;
+  }
+
+  return reinterpret_cast<void*>(ptr);
+}
+
+static void SetFencepost(uint8_t *buffer) {
+  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+    buffer[i] = 0xde;
+    buffer[i+1] = 0xad;
+  }
+}
+
+static void VerifyFencepost(uint8_t *buffer) {
+  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+    if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
+      uint8_t expected_value;
+      if (buffer[i] == 0xde) {
+        i++;
+        expected_value = 0xad;
+      } else {
+        expected_value = 0xde;
+      }
+      ASSERT_EQ(expected_value, buffer[i]);
+    }
+  }
+}
+
+void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
+  size_t min_incr = 4;
+  if (test_type == MEMSET16) {
+    min_incr = 2;
+    value |= value << 16;
+  }
+  uint32_t* expected_buf = new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)];
+  for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
+    expected_buf[i] = value;
+  }
+
+  // Allocate one large buffer with lots of extra space so that we can
+  // guarantee that all possible alignments will fit.
+  uint8_t *buf = new uint8_t[3*MAX_TEST_SIZE];
+  uint8_t *buf_align;
+  for (size_t i = 0; i < num_aligns; i++) {
+    size_t incr = min_incr;
+    for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
+      incr = GetIncrement(len, min_incr);
+
+      buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
+          buf+FENCEPOST_LENGTH, align[i][0], align[i][1]));
+
+      SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
+      SetFencepost(&buf_align[len]);
+
+      memset(buf_align, 0xff, len);
+      if (test_type == MEMSET16) {
+        android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
+      } else {
+        android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
+      }
+      ASSERT_EQ(0, memcmp(expected_buf, buf_align, len))
+          << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
+
+      VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
+      VerifyFencepost(&buf_align[len]);
+    }
+  }
+  delete expected_buf;
+  delete buf;
+}
+
+TEST(libcutils, android_memset16_non_zero) {
+  RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset16_zero) {
+  RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_non_zero) {
+  RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_zero) {
+  RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
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/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/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 484bd10..08b08fe 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,25 +135,50 @@
     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
 
+# Healthd can trigger a full boot from charger mode by signaling this
+# property when the power button is held.
+on property:sys.boot_from_charger_mode=1
+    class_stop charger
+    trigger late-init
+
+# Load properties from /system/ + /factory after fs mount.
+on load_all_props_action
+    load_all_props
+
+# Mount filesystems and start core system services.
+on late-init
+    trigger early-fs
+    trigger fs
+    trigger post-fs
+    trigger post-fs-data
+
+    # Load properties from /system/ + /factory after fs mount. Place
+    # this in another action so that the load will be scheduled after the prior
+    # issued fs triggers have completed.
+    trigger load_all_props_action
+
+    trigger early-boot
+    trigger boot
+
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
@@ -294,17 +318,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
@@ -380,8 +404,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
@@ -395,7 +419,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
@@ -435,6 +459,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}
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/nandread.c b/toolbox/nandread.c
index 971c232..bd19942 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -1,9 +1,10 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <mtd/mtd-user.h>
@@ -189,18 +190,18 @@
     for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
         bad_block = 0;
         if (verbose > 3)
-            printf("reading at %llx\n", pos);
+            printf("reading at %" PRIx64 "\n", pos);
         lseek64(fd, pos, SEEK_SET);
         ret = read(fd, buffer, mtdinfo.writesize + rawmode);
         if (ret < (int)mtdinfo.writesize) {
-            fprintf(stderr, "short read at %llx, %d\n", pos, ret);
+            fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
             bad_block = 2;
         }
         if (!rawmode) {
             oobbuf.start = pos;
             ret = ioctl(fd, MEMREADOOB, &oobbuf);
             if (ret) {
-                fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+                fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
                 bad_block = 2;
             }
         }
@@ -213,17 +214,17 @@
         bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
         ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
         if (ret && errno != EOPNOTSUPP) {
-            printf("badblock at %llx\n", pos);
+            printf("badblock at %" PRIx64 "\n", pos);
             bad_block = 1;
         }
         if (ecc.corrected != last_ecc.corrected)
-            printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
+            printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
         if (ecc.failed != last_ecc.failed)
-            printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
+            printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
         if (ecc.badblocks != last_ecc.badblocks)
-            printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
+            printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
         if (ecc.bbtblocks != last_ecc.bbtblocks)
-            printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
+            printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
 
         if (!rawmode) {
             oob_fixed = (uint8_t *)oob_data;
@@ -241,18 +242,18 @@
         if (outfd >= 0) {
             ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
             if (ret < (int)(mtdinfo.writesize + spare_size)) {
-                fprintf(stderr, "short write at %llx, %d\n", pos, ret);
+                fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
                 close(outfd);
                 outfd = -1;
             }
             if (ecc.corrected != last_ecc.corrected)
-                fprintf(statusfile, "%08llx: ecc corrected\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
             if (ecc.failed != last_ecc.failed)
-                fprintf(statusfile, "%08llx: ecc failed\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
             if (bad_block == 1)
-                fprintf(statusfile, "%08llx: badblock\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
             if (bad_block == 2)
-                fprintf(statusfile, "%08llx: read error\n", opos);
+                fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
             opos += mtdinfo.writesize + spare_size;
         }
 
@@ -261,7 +262,7 @@
         if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
             empty_pages++;
         else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
-            printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
+            printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
                    "%08x %08x %08x %08x\n", pos, oobbuf.start,
                    oob_data[0], oob_data[1], oob_data[2], oob_data[3],
                    oob_data[4], oob_data[5], oob_data[6], oob_data[7]);