Merge "logd: syscall optimization"
diff --git a/adb/Android.mk b/adb/Android.mk
index 4f19d47..3733ae3 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -161,7 +161,6 @@
     LOCAL_STATIC_LIBRARIES += libcutils
 endif
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -221,6 +220,4 @@
     libselinux \
     libext4_utils_static \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
 include $(BUILD_EXECUTABLE)
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index f9ca5ed..34efefe 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -256,29 +256,25 @@
 }
 
 #else
-static struct termios tio_save;
+static termios g_saved_terminal_state;
 
-static void stdin_raw_init(int fd)
-{
-    struct termios tio;
+static void stdin_raw_init(int fd) {
+    if (tcgetattr(fd, &g_saved_terminal_state)) return;
 
-    if(tcgetattr(fd, &tio)) return;
-    if(tcgetattr(fd, &tio_save)) return;
+    termios tio;
+    if (tcgetattr(fd, &tio)) return;
 
-    tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
+    cfmakeraw(&tio);
 
-        /* no timeout but request at least one character per read */
+    // No timeout but request at least one character per read.
     tio.c_cc[VTIME] = 0;
     tio.c_cc[VMIN] = 1;
 
-    tcsetattr(fd, TCSANOW, &tio);
-    tcflush(fd, TCIFLUSH);
+    tcsetattr(fd, TCSAFLUSH, &tio);
 }
 
-static void stdin_raw_restore(int fd)
-{
-    tcsetattr(fd, TCSANOW, &tio_save);
-    tcflush(fd, TCIFLUSH);
+static void stdin_raw_restore(int fd) {
+    tcsetattr(fd, TCSAFLUSH, &g_saved_terminal_state);
 }
 #endif
 
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 483ca3d..b150274 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -112,13 +112,13 @@
     }
 
     bool system_verified = false, vendor_verified = false;
-    property_get("partition.system.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
+    property_get("partition.system.verified", prop_buf, "");
+    if (strlen(prop_buf) > 0) {
         system_verified = true;
     }
 
-    property_get("partition.vendor.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
+    property_get("partition.vendor.verified", prop_buf, "");
+    if (strlen(prop_buf) > 0) {
         vendor_verified = true;
     }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 0a960ff..4b9eeeb 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -772,7 +772,7 @@
 }
 
 static int qual_match(const char *to_test,
-                      const char *prefix, const char *qual, int sanitize_qual)
+                      const char *prefix, const char *qual, bool sanitize_qual)
 {
     if (!to_test || !*to_test)
         /* Return true if both the qual and to_test are null strings. */
@@ -790,7 +790,7 @@
 
     while (*qual) {
         char ch = *qual++;
-        if (sanitize_qual && isalnum(ch))
+        if (sanitize_qual && !isalnum(ch))
             ch = '_';
         if (ch != *to_test++)
             return 0;
@@ -823,9 +823,9 @@
         if (serial) {
             if ((t->serial && !strcmp(serial, t->serial)) ||
                 (t->devpath && !strcmp(serial, t->devpath)) ||
-                qual_match(serial, "product:", t->product, 0) ||
-                qual_match(serial, "model:", t->model, 1) ||
-                qual_match(serial, "device:", t->device, 0)) {
+                qual_match(serial, "product:", t->product, false) ||
+                qual_match(serial, "model:", t->model, true) ||
+                qual_match(serial, "device:", t->device, false)) {
                 if (result) {
                     if (error_out)
                         *error_out = "more than one device";
@@ -918,20 +918,17 @@
 }
 
 static void add_qual(char **buf, size_t *buf_size,
-                     const char *prefix, const char *qual, int sanitize_qual)
+                     const char *prefix, const char *qual, bool sanitize_qual)
 {
-    size_t len;
-    int prefix_len;
-
     if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
         return;
 
-    len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
+    int prefix_len;
+    size_t len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
 
     if (sanitize_qual) {
-        char *cp;
-        for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
-            if (isalnum(*cp))
+        for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) {
+            if (!isalnum(*cp))
                 *cp = '_';
         }
     }
@@ -956,10 +953,10 @@
         remaining -= len;
         buf += len;
 
-        add_qual(&buf, &remaining, " ", t->devpath, 0);
-        add_qual(&buf, &remaining, " product:", t->product, 0);
-        add_qual(&buf, &remaining, " model:", t->model, 1);
-        add_qual(&buf, &remaining, " device:", t->device, 0);
+        add_qual(&buf, &remaining, " ", t->devpath, false);
+        add_qual(&buf, &remaining, " product:", t->product, false);
+        add_qual(&buf, &remaining, " model:", t->model, true);
+        add_qual(&buf, &remaining, " device:", t->device, false);
 
         len = snprintf(buf, remaining, "\n");
         remaining -= len;
diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg
index a61c08d..d94a89c 100644
--- a/base/CPPLINT.cfg
+++ b/base/CPPLINT.cfg
@@ -1,2 +1,2 @@
 set noparent
-filter=-build/header_guard,-build/include,-build/c++11
+filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
index 5e115fe..230adb8 100644
--- a/base/include/base/logging.h
+++ b/base/include/base/logging.h
@@ -17,6 +17,7 @@
 #ifndef BASE_LOGGING_H
 #define BASE_LOGGING_H
 
+#include <functional>
 #include <memory>
 #include <ostream>
 
@@ -34,6 +35,33 @@
   FATAL,
 };
 
+enum LogId {
+  DEFAULT,
+  MAIN,
+  SYSTEM,
+};
+
+typedef std::function<void(LogId, LogSeverity, const char*, const char*,
+                           unsigned int, const char*)> LogFunction;
+
+extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
+                         unsigned int, const char*);
+
+#ifdef __ANDROID__
+// We expose this even though it is the default because a user that wants to
+// override the default log buffer will have to construct this themselves.
+class LogdLogger {
+ public:
+  explicit LogdLogger(LogId default_log_id = android::base::MAIN);
+
+  void operator()(LogId, LogSeverity, const char* tag, const char* file,
+                  unsigned int line, const char* message);
+
+ private:
+  LogId default_log_id_;
+};
+#endif
+
 // Configure logging based on ANDROID_LOG_TAGS environment variable.
 // We need to parse a string that looks like
 //
@@ -42,33 +70,39 @@
 // The tag (or '*' for the global level) comes first, followed by a colon and a
 // letter indicating the minimum priority level we're expected to log.  This can
 // be used to reveal or conceal logs with specific tags.
+extern void InitLogging(char* argv[], LogFunction&& logger);
+
+// Configures logging using the default logger (logd for the device, stderr for
+// the host).
 extern void InitLogging(char* argv[]);
 
-// Returns the command line used to invoke the current tool or nullptr if
-// InitLogging hasn't been performed.
-extern const char* GetCmdLine();
-
-// The command used to start the program, such as "/system/bin/dalvikvm". If
-// InitLogging hasn't been performed then just returns "unknown"
-extern const char* ProgramInvocationName();
-
-// A short version of the command used to start the program, such as "dalvikvm".
-// If InitLogging hasn't been performed then just returns "unknown"
-extern const char* ProgramInvocationShortName();
+// Replace the current logger.
+extern void SetLogger(LogFunction&& logger);
 
 // Logs a message to logcat on Android otherwise to stderr. If the severity is
 // FATAL it also causes an abort. For example:
 //
 //     LOG(FATAL) << "We didn't expect to reach here";
-#define LOG(severity)                                                        \
-  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::severity, \
-                              -1).stream()
+#define LOG(severity)                                                       \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::severity, -1).stream()
+
+// Logs a message to logcat with the specified log ID on Android otherwise to
+// stderr. If the severity is FATAL it also causes an abort.
+#define LOG_TO(dest, severity)                                           \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+                              ::android::base::severity, -1).stream()
 
 // A variant of LOG that also logs the current errno value. To be used when
 // library calls fail.
-#define PLOG(severity)                                                       \
-  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::severity, \
-                              errno).stream()
+#define PLOG(severity)                                                      \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::severity, errno).stream()
+
+// Behaves like PLOG, but logs to the specified log ID.
+#define PLOG_TO(dest, severity)                                          \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+                              ::android::base::severity, errno).stream()
 
 // Marker that code is yet to be implemented.
 #define UNIMPLEMENTED(level) \
@@ -82,18 +116,18 @@
 //       "Check failed: false == true".
 #define CHECK(x)                                                            \
   if (UNLIKELY(!(x)))                                                       \
-    ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, \
-                                -1).stream()                                \
-        << "Check failed: " #x << " "
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::FATAL, -1).stream()          \
+      << "Check failed: " #x << " "
 
 // Helper for CHECK_xx(x,y) macros.
-#define CHECK_OP(LHS, RHS, OP)                                                \
-  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);          \
-       UNLIKELY(!(_values.lhs OP _values.rhs));                               \
-       /* empty */)                                                           \
-  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, -1) \
-          .stream()                                                           \
-      << "Check failed: " << #LHS << " " << #OP << " " << #RHS                \
+#define CHECK_OP(LHS, RHS, OP)                                              \
+  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);        \
+       UNLIKELY(!(_values.lhs OP _values.rhs));                             \
+       /* empty */)                                                         \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::FATAL, -1).stream()          \
+      << "Check failed: " << #LHS << " " << #OP << " " << #RHS              \
       << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
 
 // Check whether a condition holds between x and y, LOG(FATAL) if not. The value
@@ -228,8 +262,8 @@
 // of a CHECK. The destructor will abort if the severity is FATAL.
 class LogMessage {
  public:
-  LogMessage(const char* file, unsigned int line, LogSeverity severity,
-             int error);
+  LogMessage(const char* file, unsigned int line, LogId id,
+             LogSeverity severity, int error);
 
   ~LogMessage();
 
@@ -238,12 +272,8 @@
   std::ostream& stream();
 
   // The routine that performs the actual logging.
-  static void LogLine(const char* file, unsigned int line, LogSeverity severity,
-                      const char* msg);
-
-  // A variant of the above for use with little stack.
-  static void LogLineLowStack(const char* file, unsigned int line,
-                              LogSeverity severity, const char* msg);
+  static void LogLine(const char* file, unsigned int line, LogId id,
+                      LogSeverity severity, const char* msg);
 
  private:
   const std::unique_ptr<LogMessageData> data_;
diff --git a/base/include/base/memory.h b/base/include/base/memory.h
new file mode 100644
index 0000000..882582f
--- /dev/null
+++ b/base/include/base/memory.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BASE_MEMORY_H
+#define BASE_MEMORY_H
+
+namespace android {
+namespace base {
+
+// Use packed structures for access to unaligned data on targets with alignment
+// restrictions.  The compiler will generate appropriate code to access these
+// structures without generating alignment exceptions.
+template <typename T>
+static inline T get_unaligned(const T* address) {
+  struct unaligned {
+    T v;
+  } __attribute__((packed));
+  const unaligned* p = reinterpret_cast<const unaligned*>(address);
+  return p->v;
+}
+
+template <typename T>
+static inline void put_unaligned(T* address, T v) {
+  struct unaligned {
+    T v;
+  } __attribute__((packed));
+  unaligned* p = reinterpret_cast<unaligned*>(address);
+  p->v = v;
+}
+
+} // namespace base
+} // namespace android
+
+#endif // BASE_MEMORY_H
diff --git a/base/logging.cpp b/base/logging.cpp
index 38ee2af..0142b70 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -16,11 +16,21 @@
 
 #include "base/logging.h"
 
+#include <libgen.h>
+
+// For getprogname(3) or program_invocation_short_name.
+#if defined(__ANDROID__) || defined(__APPLE__)
+#include <stdlib.h>
+#elif defined(__GLIBC__)
+#include <errno.h>
+#endif
+
 #include <iostream>
 #include <limits>
 #include <mutex>
 #include <sstream>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/strings.h"
@@ -40,49 +50,96 @@
 
 static std::mutex logging_lock;
 
+#ifdef __ANDROID__
+static LogFunction gLogger = LogdLogger();
+#else
+static LogFunction gLogger = StderrLogger;
+#endif
+
+static bool gInitialized = false;
 static LogSeverity gMinimumLogSeverity = INFO;
-static std::unique_ptr<std::string> gCmdLine;
 static std::unique_ptr<std::string> gProgramInvocationName;
-static std::unique_ptr<std::string> gProgramInvocationShortName;
 
-const char* GetCmdLine() {
-  return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
+#if defined(__GLIBC__)
+static const char* getprogname() {
+  return program_invocation_short_name;
+}
+#endif
+
+static const char* ProgramInvocationName() {
+  if (gProgramInvocationName == nullptr) {
+    gProgramInvocationName.reset(new std::string(getprogname()));
+  }
+
+  return gProgramInvocationName->c_str();
 }
 
-const char* ProgramInvocationName() {
-  return (gProgramInvocationName.get() != nullptr)
-             ? gProgramInvocationName->c_str()
-             : "unknown";
+void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
+                  unsigned int line, const char* message) {
+  static const char* log_characters = "VDIWEF";
+  CHECK_EQ(strlen(log_characters), FATAL + 1U);
+  char severity_char = log_characters[severity];
+  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
+          severity_char, getpid(), gettid(), file, line, message);
 }
 
-const char* ProgramInvocationShortName() {
-  return (gProgramInvocationShortName.get() != nullptr)
-             ? gProgramInvocationShortName->c_str()
-             : "unknown";
+
+#ifdef __ANDROID__
+LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
+}
+
+static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+    ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
+};
+static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
+              "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
+              "in LogSeverity");
+
+static const log_id kLogIdToAndroidLogId[] = {
+    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
+};
+static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
+              "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
+
+void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
+                            const char* file, unsigned int line,
+                            const char* message) {
+  int priority = kLogSeverityToAndroidLogPriority[severity];
+  if (id == DEFAULT) {
+    id = default_log_id_;
+  }
+
+  log_id lg_id = kLogIdToAndroidLogId[id];
+
+  if (priority == ANDROID_LOG_FATAL) {
+    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
+                            message);
+  } else {
+    __android_log_buf_print(lg_id, priority, tag, "%s", message);
+  }
+}
+#endif
+
+void InitLogging(char* argv[], LogFunction&& logger) {
+  SetLogger(std::forward<LogFunction>(logger));
+  InitLogging(argv);
 }
 
 void InitLogging(char* argv[]) {
-  if (gCmdLine.get() != nullptr) {
+  if (gInitialized) {
     return;
   }
 
+  gInitialized = true;
+
   // Stash the command line for later use. We can use /proc/self/cmdline on
   // Linux to recover this, but we don't have that luxury on the Mac, and there
   // are a couple of argv[0] variants that are commonly used.
   if (argv != nullptr) {
-    gCmdLine.reset(new std::string(argv[0]));
-    for (size_t i = 1; argv[i] != nullptr; ++i) {
-      gCmdLine->append(" ");
-      gCmdLine->append(argv[i]);
-    }
-    gProgramInvocationName.reset(new std::string(argv[0]));
-    const char* last_slash = strrchr(argv[0], '/');
-    gProgramInvocationShortName.reset(
-        new std::string((last_slash != nullptr) ? last_slash + 1 : argv[0]));
-  } else {
-    // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux.
-    gCmdLine.reset(new std::string("<unset>"));
+    gProgramInvocationName.reset(new std::string(basename(argv[0])));
   }
+
   const char* tags = getenv("ANDROID_LOG_TAGS");
   if (tags == nullptr) {
     return;
@@ -124,13 +181,22 @@
   }
 }
 
+void SetLogger(LogFunction&& logger) {
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gLogger = std::move(logger);
+}
+
 // This indirection greatly reduces the stack impact of having lots of
 // checks/logging in a function.
 class LogMessageData {
  public:
-  LogMessageData(const char* file, unsigned int line, LogSeverity severity,
-                 int error)
-      : file_(file), line_number_(line), severity_(severity), error_(error) {
+  LogMessageData(const char* file, unsigned int line, LogId id,
+                 LogSeverity severity, int error)
+      : file_(file),
+        line_number_(line),
+        id_(id),
+        severity_(severity),
+        error_(error) {
     const char* last_slash = strrchr(file, '/');
     file = (last_slash == nullptr) ? file : last_slash + 1;
   }
@@ -147,6 +213,10 @@
     return severity_;
   }
 
+  LogId GetId() const {
+    return id_;
+  }
+
   int GetError() const {
     return error_;
   }
@@ -163,15 +233,16 @@
   std::ostringstream buffer_;
   const char* const file_;
   const unsigned int line_number_;
+  const LogId id_;
   const LogSeverity severity_;
   const int error_;
 
   DISALLOW_COPY_AND_ASSIGN(LogMessageData);
 };
 
-LogMessage::LogMessage(const char* file, unsigned int line,
+LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
                        LogSeverity severity, int error)
-    : data_(new LogMessageData(file, line, severity, error)) {
+    : data_(new LogMessageData(file, line, id, severity, error)) {
 }
 
 LogMessage::~LogMessage() {
@@ -185,22 +256,18 @@
   }
   std::string msg(data_->ToString());
 
-  // Do the actual logging with the lock held.
-  {
-    std::lock_guard<std::mutex> lock(logging_lock);
-    if (msg.find('\n') == std::string::npos) {
-      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(),
-              msg.c_str());
-    } else {
-      msg += '\n';
-      size_t i = 0;
-      while (i < msg.size()) {
-        size_t nl = msg.find('\n', i);
-        msg[nl] = '\0';
-        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(),
-                &msg[i]);
-        i = nl + 1;
-      }
+  if (msg.find('\n') == std::string::npos) {
+    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
+            data_->GetSeverity(), msg.c_str());
+  } else {
+    msg += '\n';
+    size_t i = 0;
+    while (i < msg.size()) {
+      size_t nl = msg.find('\n', i);
+      msg[nl] = '\0';
+      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
+              data_->GetSeverity(), &msg[i]);
+      i = nl + 1;
     }
   }
 
@@ -217,76 +284,11 @@
   return data_->GetBuffer();
 }
 
-#ifdef __ANDROID__
-static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
-    ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
-    ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
-static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
-              "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
-              "in LogSeverity");
-#endif
-
-void LogMessage::LogLine(const char* file, unsigned int line,
-                         LogSeverity log_severity, const char* message) {
-#ifdef __ANDROID__
-  const char* tag = ProgramInvocationShortName();
-  int priority = kLogSeverityToAndroidLogPriority[log_severity];
-  if (priority == ANDROID_LOG_FATAL) {
-    LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
-  } else {
-    LOG_PRI(priority, tag, "%s", message);
-  }
-#else
-  static const char* log_characters = "VDIWEF";
-  CHECK_EQ(strlen(log_characters), FATAL + 1U);
-  char severity = log_characters[log_severity];
-  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(),
-          severity, getpid(), gettid(), file, line, message);
-#endif
-}
-
-void LogMessage::LogLineLowStack(const char* file, unsigned int line,
-                                 LogSeverity log_severity, const char* message) {
-#ifdef __ANDROID__
-  // Use android_writeLog() to avoid stack-based buffers used by
-  // android_printLog().
-  const char* tag = ProgramInvocationShortName();
-  int priority = kLogSeverityToAndroidLogPriority[log_severity];
-  char* buf = nullptr;
-  size_t buf_size = 0u;
-  if (priority == ANDROID_LOG_FATAL) {
-    // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line,
-    // message) below.  If allocation fails, fall back to printing only the
-    // message.
-    buf_size = strlen(file) + 1 /* ':' */ +
-               std::numeric_limits<typeof(line)>::max_digits10 + 2 /* "] " */ +
-               strlen(message) + 1 /* terminating 0 */;
-    buf = reinterpret_cast<char*>(malloc(buf_size));
-  }
-  if (buf != nullptr) {
-    snprintf(buf, buf_size, "%s:%u] %s", file, line, message);
-    android_writeLog(priority, tag, buf);
-    free(buf);
-  } else {
-    android_writeLog(priority, tag, message);
-  }
-#else
-  static const char* log_characters = "VDIWEF";
-  CHECK_EQ(strlen(log_characters), FATAL + 1U);
-
-  const char* program_name = ProgramInvocationShortName();
-  write(STDERR_FILENO, program_name, strlen(program_name));
-  write(STDERR_FILENO, " ", 1);
-  write(STDERR_FILENO, &log_characters[log_severity], 1);
-  write(STDERR_FILENO, " ", 1);
-  // TODO: pid and tid.
-  write(STDERR_FILENO, file, strlen(file));
-  // TODO: line.
-  UNUSED(line);
-  write(STDERR_FILENO, "] ", 2);
-  write(STDERR_FILENO, message, strlen(message));
-  write(STDERR_FILENO, "\n", 1);
-#endif
+void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
+                         LogSeverity severity, const char* message) {
+  const char* tag = ProgramInvocationName();
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gLogger(id, severity, tag, file, line, message);
 }
 
 ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 0a03e38..d947c1d 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -61,7 +61,7 @@
   int old_stderr_;
 };
 
-HOST_TEST(logging, CHECK) {
+TEST(logging, CHECK) {
   ASSERT_DEATH(CHECK(false), "Check failed: false ");
   CHECK(true);
 
@@ -82,7 +82,7 @@
       log_char, message);
 }
 
-HOST_TEST(logging, LOG) {
+TEST(logging, LOG) {
   ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar");
 
   {
@@ -136,7 +136,7 @@
   }
 }
 
-HOST_TEST(logging, PLOG) {
+TEST(logging, PLOG) {
   {
     CapturedStderr cap;
     errno = ENOENT;
@@ -152,7 +152,7 @@
   }
 }
 
-HOST_TEST(logging, UNIMPLEMENTED) {
+TEST(logging, UNIMPLEMENTED) {
   {
     CapturedStderr cap;
     errno = ENOENT;
diff --git a/base/test_main.cpp b/base/test_main.cpp
index c49ca4b..546923d 100644
--- a/base/test_main.cpp
+++ b/base/test_main.cpp
@@ -20,6 +20,6 @@
 
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
-  android::base::InitLogging(argv);
+  android::base::InitLogging(argv, android::base::StderrLogger);
   return RUN_ALL_TESTS();
 }
diff --git a/cpio/Android.mk b/cpio/Android.mk
index 575beb2..b9d18ba 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -10,6 +10,8 @@
 
 LOCAL_CFLAGS := -Werror
 
+LOCAL_STATIC_LIBRARIES := libcutils
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
index 764b9db..5ea03e7 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/elf_utils.cpp
@@ -29,6 +29,8 @@
 
 #include "elf_utils.h"
 
+#define NOTE_ALIGN(size)  ((size + 3) & ~3)
+
 template <typename HdrType, typename PhdrType, typename NhdrType>
 static bool get_build_id(
     Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
@@ -60,7 +62,7 @@
         addr += sizeof(nhdr);
         if (nhdr.n_type == NT_GNU_BUILD_ID) {
           // Skip the name (which is the owner and should be "GNU").
-          addr += nhdr.n_namesz;
+          addr += NOTE_ALIGN(nhdr.n_namesz);
           uint8_t build_id_data[128];
           if (nhdr.n_namesz > sizeof(build_id_data)) {
             ALOGE("Possible corrupted note, name size value is too large: %u",
@@ -80,7 +82,7 @@
         } else {
           // Move past the extra note data.
           hdr_size -= sizeof(nhdr);
-          size_t skip_bytes = nhdr.n_namesz + nhdr.n_descsz;
+          size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
           addr += skip_bytes;
           if (hdr_size < skip_bytes) {
             break;
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 61bf1ee..08d0671 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -8,8 +8,8 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
 LOCAL_MODULE:= libfs_mgr
-LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
-LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libsquashfs_utils
+LOCAL_C_INCLUDES += system/extras/ext4_utils system/extras/squashfs_utils
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Werror
 
@@ -34,7 +34,8 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
+LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static libsquashfs_utils
+LOCAL_CXX_STL := libc++_static
 
 LOCAL_CFLAGS := -Werror
 
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index acdc5a3..6ef46ba 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -38,6 +38,7 @@
 #include "mincrypt/sha256.h"
 
 #include "ext4_sb.h"
+#include "squashfs_utils.h"
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
@@ -51,6 +52,8 @@
 #define METADATA_TAG_MAX_LENGTH 63
 #define METADATA_EOD "eod"
 
+#define VERITY_LASTSIG_TAG "verity_lastsig"
+
 #define VERITY_STATE_TAG "verity_state"
 #define VERITY_STATE_HEADER 0x83c0ae9d
 #define VERITY_STATE_VERSION 1
@@ -138,7 +141,19 @@
     return retval;
 }
 
-static int get_target_device_size(char *blk_device, uint64_t *device_size)
+static int squashfs_get_target_device_size(char *blk_device, uint64_t *device_size)
+{
+    struct squashfs_info sq_info;
+
+    if (squashfs_parse_sb(blk_device, &sq_info) >= 0) {
+        *device_size = sq_info.bytes_used_4K_padded;
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+static int ext4_get_target_device_size(char *blk_device, uint64_t *device_size)
 {
     int data_device;
     struct ext4_super_block sb;
@@ -171,16 +186,38 @@
     return 0;
 }
 
-static int read_verity_metadata(char *block_device, char **signature, char **table)
+static int get_fs_size(char *fs_type, char *blk_device, uint64_t *device_size) {
+    if (!strcmp(fs_type, "ext4")) {
+        if (ext4_get_target_device_size(blk_device, device_size) < 0) {
+            ERROR("Failed to get ext4 fs size on %s.", blk_device);
+            return -1;
+        }
+    } else if (!strcmp(fs_type, "squashfs")) {
+        if (squashfs_get_target_device_size(blk_device, device_size) < 0) {
+            ERROR("Failed to get squashfs fs size on %s.", blk_device);
+            return -1;
+        }
+    } else {
+        ERROR("%s: Unsupported filesystem for verity.", fs_type);
+        return -1;
+    }
+    return 0;
+}
+
+static int read_verity_metadata(uint64_t device_size, char *block_device, char **signature,
+        char **table)
 {
     unsigned magic_number;
     unsigned table_length;
-    uint64_t device_length;
     int protocol_version;
     int device;
     int retval = FS_MGR_SETUP_VERITY_FAIL;
-    *signature = 0;
-    *table = 0;
+
+    *signature = NULL;
+
+    if (table) {
+        *table = NULL;
+    }
 
     device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC));
     if (device == -1) {
@@ -188,12 +225,7 @@
         goto out;
     }
 
-    // find the start of the verity metadata
-    if (get_target_device_size(block_device, &device_length) < 0) {
-        ERROR("Could not get target device size.\n");
-        goto out;
-    }
-    if (TEMP_FAILURE_RETRY(lseek64(device, device_length, SEEK_SET)) < 0) {
+    if (TEMP_FAILURE_RETRY(lseek64(device, device_size, SEEK_SET)) < 0) {
         ERROR("Could not seek to start of verity metadata block.\n");
         goto out;
     }
@@ -214,8 +246,7 @@
 #endif
 
     if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
-        ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n",
-              device_length);
+        ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_size);
         goto out;
     }
 
@@ -241,6 +272,11 @@
         goto out;
     }
 
+    if (!table) {
+        retval = FS_MGR_SETUP_VERITY_SUCCESS;
+        goto out;
+    }
+
     // get the size of the table
     if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) !=
             sizeof(table_length)) {
@@ -268,10 +304,13 @@
         TEMP_FAILURE_RETRY(close(device));
 
     if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
-        free(*table);
         free(*signature);
-        *table = 0;
-        *signature = 0;
+        *signature = NULL;
+
+        if (table) {
+            free(*table);
+            *table = NULL;
+        }
     }
 
     return retval;
@@ -316,17 +355,12 @@
     return 0;
 }
 
-static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table,
+static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd, char *table,
         int mode)
 {
     char *verity_params;
     char *buffer = (char*) io;
     size_t bufsize;
-    uint64_t device_size = 0;
-
-    if (get_target_device_size(blockdev, &device_size) < 0) {
-        return -1;
-    }
 
     verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
 
@@ -594,46 +628,29 @@
     return rc;
 }
 
-static int load_verity_state(struct fstab_rec *fstab, int *mode)
+static int read_verity_state(const char *fname, off64_t offset, int *mode)
 {
     int fd = -1;
     int rc = -1;
-    off64_t offset = 0;
     struct verity_state s;
 
-    if (metadata_find(fstab->verity_loc, VERITY_STATE_TAG, sizeof(s),
-            &offset) < 0) {
-        /* fall back to stateless behavior */
-        *mode = VERITY_MODE_EIO;
-        rc = 0;
-        goto out;
-    }
-
-    if (was_verity_restart()) {
-        /* device was restarted after dm-verity detected a corrupted
-         * block, so switch to logging mode */
-        *mode = VERITY_MODE_LOGGING;
-        rc = write_verity_state(fstab->verity_loc, offset, *mode);
-        goto out;
-    }
-
-    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDONLY | O_CLOEXEC));
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
 
     if (fd == -1) {
-        ERROR("Failed to open %s (%s)\n", fstab->verity_loc, strerror(errno));
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
         goto out;
     }
 
     if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
         ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
-            sizeof(s), fstab->verity_loc, offset, strerror(errno));
+            sizeof(s), fname, offset, strerror(errno));
         goto out;
     }
 
     if (s.header != VERITY_STATE_HEADER) {
         /* space allocated, but no state written. write default state */
         *mode = VERITY_MODE_DEFAULT;
-        rc = write_verity_state(fstab->verity_loc, offset, *mode);
+        rc = write_verity_state(fname, offset, *mode);
         goto out;
     }
 
@@ -659,14 +676,133 @@
     return rc;
 }
 
+static int compare_last_signature(struct fstab_rec *fstab, int *match)
+{
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+    char *signature = NULL;
+    int fd = -1;
+    int rc = -1;
+    uint8_t curr[SHA256_DIGEST_SIZE];
+    uint8_t prev[SHA256_DIGEST_SIZE];
+    off64_t offset = 0;
+    uint64_t device_size;
+
+    *match = 1;
+
+    // get verity filesystem size
+    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
+        ERROR("Failed to get filesystem size\n");
+        goto out;
+    }
+
+    if (read_verity_metadata(device_size, fstab->blk_device, &signature, NULL) < 0) {
+        ERROR("Failed to read verity signature from %s\n", fstab->mount_point);
+        goto out;
+    }
+
+    SHA256_hash(signature, RSANUMBYTES, curr);
+
+    if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
+            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
+        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
+        goto out;
+    }
+
+    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
+            &offset) < 0) {
+        goto out;
+    }
+
+    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s: %s\n", fstab->verity_loc, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
+            offset)) != sizeof(prev)) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
+            sizeof(prev), fstab->verity_loc, offset, strerror(errno));
+        goto out;
+    }
+
+    *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
+
+    if (!*match) {
+        /* update current signature hash */
+        if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
+                offset)) != sizeof(curr)) {
+            ERROR("Failed to write %zu bytes to %s offset %" PRIu64 " (%s)\n",
+                sizeof(curr), fstab->verity_loc, offset, strerror(errno));
+            goto out;
+        }
+    }
+
+    rc = 0;
+
+out:
+    free(signature);
+
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
+{
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+
+    if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
+            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
+        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
+        return -1;
+    }
+
+    return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
+                offset);
+}
+
+static int load_verity_state(struct fstab_rec *fstab, int *mode)
+{
+    off64_t offset = 0;
+    int match = 0;
+
+    if (get_verity_state_offset(fstab, &offset) < 0) {
+        /* fall back to stateless behavior */
+        *mode = VERITY_MODE_EIO;
+        return 0;
+    }
+
+    if (was_verity_restart()) {
+        /* device was restarted after dm-verity detected a corrupted
+         * block, so switch to logging mode */
+        *mode = VERITY_MODE_LOGGING;
+        return write_verity_state(fstab->verity_loc, offset, *mode);
+    }
+
+    if (!compare_last_signature(fstab, &match) && !match) {
+        /* partition has been reflashed, reset dm-verity state */
+        *mode = VERITY_MODE_DEFAULT;
+        return write_verity_state(fstab->verity_loc, offset, *mode);
+    }
+
+    return read_verity_state(fstab->verity_loc, offset, mode);
+}
+
 int fs_mgr_load_verity_state(int *mode)
 {
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     char propbuf[PROPERTY_VALUE_MAX];
     int rc = -1;
     int i;
+    int current;
     struct fstab *fstab = NULL;
 
+    /* return the default mode, unless any of the verified partitions are in
+     * logging mode, in which case return that */
     *mode = VERITY_MODE_DEFAULT;
 
     property_get("ro.hardware", propbuf, "");
@@ -684,20 +820,16 @@
             continue;
         }
 
-        rc = load_verity_state(&fstab->recs[i], mode);
+        rc = load_verity_state(&fstab->recs[i], &current);
         if (rc < 0) {
             continue;
         }
 
-        /* if any of the verified partitions are in logging mode, return */
-        if (*mode == VERITY_MODE_LOGGING) {
-            rc = 0;
-            goto out;
+        if (current == VERITY_MODE_LOGGING) {
+            *mode = current;
         }
     }
 
-    /* if there were multiple partitions, all in non-logging mode, return the
-     * state of the last one */
     rc = 0;
 
 out:
@@ -717,6 +849,7 @@
     char *status;
     int fd = -1;
     int i;
+    int mode;
     int rc = -1;
     off64_t offset = 0;
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -744,8 +877,8 @@
             continue;
         }
 
-        if (metadata_find(fstab->recs[i].verity_loc, VERITY_STATE_TAG,
-                sizeof(struct verity_state), &offset) < 0) {
+        if (get_verity_state_offset(&fstab->recs[i], &offset) < 0 ||
+            read_verity_state(fstab->recs[i].verity_loc, offset, &mode) < 0) {
             continue;
         }
 
@@ -755,26 +888,23 @@
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
             ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
                 strerror(errno));
-            goto out;
+            continue;
         }
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
         if (*status == 'C') {
-            rc = write_verity_state(fstab->recs[i].verity_loc, offset,
-                    VERITY_MODE_LOGGING);
-
-            if (rc == -1) {
-                goto out;
+            if (write_verity_state(fstab->recs[i].verity_loc, offset,
+                    VERITY_MODE_LOGGING) < 0) {
+                continue;
             }
         }
 
         if (callback) {
-            callback(&fstab->recs[i], mount_point, *status);
+            callback(&fstab->recs[i], mount_point, mode, *status);
         }
     }
 
-    /* Don't overwrite possible previous state if there's no corruption. */
     rc = 0;
 
 out:
@@ -798,6 +928,7 @@
     char *verity_blk_name = 0;
     char *verity_table = 0;
     char *verity_table_signature = 0;
+    uint64_t device_size = 0;
 
     _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -807,16 +938,15 @@
     io->flags |= 1;
     io->target_count = 1;
 
-    // check to ensure that the verity device is ext4
-    // TODO: support non-ext4 filesystems
-    if (strcmp(fstab->fs_type, "ext4")) {
-        ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type);
+    // get verity filesystem size
+    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
         return retval;
     }
 
     // read the verity block at the end of the block device
     // send error code up the chain so we can detect attempts to disable verity
-    retval = read_verity_metadata(fstab->blk_device,
+    retval = read_verity_metadata(device_size,
+                                  fstab->blk_device,
                                   &verity_table_signature,
                                   &verity_table);
     if (retval < 0) {
@@ -861,7 +991,7 @@
     INFO("Enabling dm-verity for %s (mode %d)\n",  mount_point, mode);
 
     // load the verity mapping table
-    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table,
+    if (load_verity_table(io, mount_point, device_size, fd, verity_table,
             mode) < 0) {
         goto out;
     }
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index b5e02f9..c58a888 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -69,7 +69,7 @@
 
 // Callback function for verity status
 typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
-        const char *mount_point, int status);
+        const char *mount_point, int mode, int status);
 
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
diff --git a/include/cutils/memory.h b/include/cutils/memory.h
index e725cdd..4d26882 100644
--- a/include/cutils/memory.h
+++ b/include/cutils/memory.h
@@ -30,7 +30,7 @@
 /* size is given in bytes and must be multiple of 4 */
 void android_memset32(uint32_t* dst, uint32_t value, size_t size);
 
-#if !HAVE_STRLCPY
+#if defined(__GLIBC__) || defined(_WIN32)
 /* Declaration of strlcpy() for platforms that don't already have it. */
 size_t strlcpy(char *dst, const char *src, size_t size);
 #endif
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index c47588c..f8076ca 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -18,6 +18,7 @@
 #define __CUTILS_SOCKETS_H
 
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
@@ -46,30 +47,19 @@
  */
 static inline int android_get_control_socket(const char *name)
 {
-	char key[64] = ANDROID_SOCKET_ENV_PREFIX;
-	const char *val;
-	int fd;
+	char key[64];
+	snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
 
-	/* build our environment variable, counting cycles like a wolf ... */
-#if HAVE_STRLCPY
-	strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-		name,
-		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-#else	/* for the host, which may lack the almightly strncpy ... */
-	strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-		name,
-		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-	key[sizeof(key)-1] = '\0';
-#endif
-
-	val = getenv(key);
-	if (!val)
+	const char* val = getenv(key);
+	if (!val) {
 		return -1;
+	}
 
 	errno = 0;
-	fd = strtol(val, NULL, 10);
-	if (errno)
+	int fd = strtol(val, NULL, 10);
+	if (errno) {
 		return -1;
+	}
 
 	return fd;
 }
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 66f3637..aa1435a 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -18,6 +18,9 @@
 #define __CUTILS_STR_PARMS_H
 
 #include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
 
 struct str_parms;
 
@@ -52,4 +55,6 @@
 /* debug */
 void str_parms_dump(struct str_parms *str_parms);
 
+__END_DECLS
+
 #endif /* __CUTILS_STR_PARMS_H */
diff --git a/include/log/log.h b/include/log/log.h
index 99015db..ce253e2 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -67,6 +67,23 @@
 
 // ---------------------------------------------------------------------
 
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
+/*
+ *      -DLINT_RLOG in sources that you want to enforce that all logging
+ * goes to the radio log buffer. If any logging goes to any of the other
+ * log buffers, there will be a compile or link error to highlight the
+ * problem. This is not a replacement for a full audit of the code since
+ * this only catches compiled code, not ifdef'd debug code. Options to
+ * defining this, either temporarily to do a spot check, or permanently
+ * to enforce, in all the communications trees; We have hopes to ensure
+ * that by supplying just the radio log buffer that the communications
+ * teams will have their one-stop shop for triaging issues.
+ */
+#ifndef LINT_RLOG
+
 /*
  * Simplified macro to send a verbose log message using the current LOG_TAG.
  */
@@ -79,10 +96,6 @@
 #endif
 #endif
 
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
 #ifndef ALOGV_IF
 #if LOG_NDEBUG
 #define ALOGV_IF(cond, ...)   ((void)0)
@@ -283,6 +296,8 @@
     : (void)0 )
 #endif
 
+#endif /* !LINT_RLOG */
+
 // ---------------------------------------------------------------------
 
 /*
@@ -567,11 +582,15 @@
 typedef enum log_id {
     LOG_ID_MIN = 0,
 
+#ifndef LINT_RLOG
     LOG_ID_MAIN = 0,
+#endif
     LOG_ID_RADIO = 1,
+#ifndef LINT_RLOG
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
+#endif
 
     LOG_ID_MAX
 } log_id_t;
diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h
index 0505cda..b92d3db 100644
--- a/include/private/android_filesystem_capability.h
+++ b/include/private/android_filesystem_capability.h
@@ -105,7 +105,9 @@
 #define CAP_MAC_ADMIN 33
 #define CAP_SYSLOG 34
 #define CAP_WAKE_ALARM 35
-#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define CAP_BLOCK_SUSPEND 36
+#define CAP_AUDIT_READ 37
+#define CAP_LAST_CAP CAP_AUDIT_READ
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 #define CAP_TO_INDEX(x) ((x) >> 5)
 #define CAP_TO_MASK(x) (1 << ((x) & 31))
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index a3d11a7..fed81f8 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -22,8 +22,7 @@
 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
 #define _ANDROID_FILESYSTEM_CONFIG_H_
 
-#include <string.h>
-#include <sys/stat.h>
+#include <sys/cdefs.h>
 #include <sys/types.h>
 #include <stdint.h>
 
@@ -114,6 +113,14 @@
 #define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */
 
 #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
+/*
+ * Used in:
+ *  bionic/libc/bionic/stubs.cpp
+ *  external/libselinux/src/android.c
+ *  system/core/logd/LogStatistics.cpp
+ *  system/core/init/ueventd.cpp
+ *  system/core/init/util.cpp
+ */
 struct android_id_info {
     const char *name;
     unsigned aid;
@@ -191,116 +198,24 @@
     const char *prefix;
 };
 
-/* Rules for directories.
-** These rules are applied based on "first match", so they
-** should start with the most specific path and work their
-** way up to the root.
-*/
+/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */
 
-static const struct fs_path_config android_dirs[] = {
-    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
-    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
-    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
-    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
-    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
-    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
-    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
-    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
-    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
-    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
-    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
-    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
-    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
-};
+__BEGIN_DECLS
 
-/* Rules for files.
-** These rules are applied based on "first match", so they
-** should start with the most specific path and work their
-** way up to the root. Prefixes ending in * denotes wildcard
-** and will allow partial matches.
-*/
-static const struct fs_path_config android_files[] = {
-    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
-    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
-    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
-    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
-    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
-    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
-    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
-    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
-    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
-    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+/*
+ * Used in:
+ *  build/tools/fs_config/fs_config.c
+ *  build/tools/fs_get_stats/fs_get_stats.c
+ *  external/genext2fs/genext2fs.c
+ *  external/squashfs-tools/squashfs-tools/android.c
+ *  system/core/cpio/mkbootfs.c
+ *  system/core/adb/file_sync_service.cpp
+ *  system/extras/ext4_utils/canned_fs_config.c
+ */
+void fs_config(const char *path, int dir,
+               unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
 
-    /* the following five files are INTENTIONALLY set-uid, but they
-     * are NOT included on user builds. */
-    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
-    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+__END_DECLS
 
-    /* the following files have enhanced capabilities and ARE included in user builds. */
-    { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
-
-    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
-    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
-    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
-    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
-};
-
-static inline void fs_config(const char *path, int dir,
-                             unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
-{
-    const struct fs_path_config *pc;
-    int plen;
-
-    if (path[0] == '/') {
-        path++;
-    }
-
-    pc = dir ? android_dirs : android_files;
-    plen = strlen(path);
-    for(; pc->prefix; pc++){
-        int len = strlen(pc->prefix);
-        if (dir) {
-            if(plen < len) continue;
-            if(!strncmp(pc->prefix, path, len)) break;
-            continue;
-        }
-        /* If name ends in * then allow partial matches. */
-        if (pc->prefix[len -1] == '*') {
-            if(!strncmp(pc->prefix, path, len - 1)) break;
-        } else if (plen == len){
-            if(!strncmp(pc->prefix, path, len)) break;
-        }
-    }
-    *uid = pc->uid;
-    *gid = pc->gid;
-    *mode = (*mode & (~07777)) | pc->mode;
-    *capabilities = pc->capabilities;
-
-#if 0
-    fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
-            path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
-#endif
-}
 #endif
 #endif
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index 724ca51..04238a6 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -70,7 +70,17 @@
     android_event_long_t payload;
 } android_log_event_long_t;
 
-/* Event payload EVENT_TYPE_STRING */
+/*
+ * Event payload EVENT_TYPE_STRING
+ *
+ * Danger: do not embed this structure into another structure.
+ * This structure uses a flexible array member, and when
+ * compiled using g++, __builtin_object_size(data, 1) returns
+ * a bad value. This is possibly a g++ bug, or a bug due to
+ * the fact that flexible array members are not supported
+ * in C++.
+ * http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c
+ */
 typedef struct __attribute__((__packed__)) {
     int8_t type;    // EVENT_TYPE_STRING;
     int32_t length; // Little Endian Order
@@ -80,7 +90,9 @@
 /* Event with single EVENT_TYPE_STRING */
 typedef struct __attribute__((__packed__)) {
     android_event_header_t header;
-    android_event_string_t payload;
+    int8_t type;    // EVENT_TYPE_STRING;
+    int32_t length; // Little Endian Order
+    char data[];
 } android_log_event_string_t;
 
 #endif
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
index ca4a8e0..7d96310 100644
--- a/include/utils/Compat.h
+++ b/include/utils/Compat.h
@@ -41,12 +41,12 @@
 #define DEFFILEMODE 0666
 #endif /* _WIN32 */
 
-#if HAVE_PRINTF_ZD
-#  define ZD "%zd"
-#  define ZD_TYPE ssize_t
+#if defined(_WIN32)
+#define ZD "%ld"
+#define ZD_TYPE long
 #else
-#  define ZD "%ld"
-#  define ZD_TYPE long
+#define ZD "%zd"
+#define ZD_TYPE ssize_t
 #endif
 
 /*
diff --git a/init/Android.mk b/init/Android.mk
index 9d91a3f..4bd4f3d 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -58,6 +58,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libinit \
     libfs_mgr \
+    libsquashfs_utils \
     liblogwrap \
     libcutils \
     libbase \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 9d5b8a8..3bbaf83 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -154,68 +154,6 @@
     return 0;
 }
 
-// TODO: remove execonce when exec is available.
-int do_execonce(int nargs, char **args)
-{
-    pid_t child;
-    int child_status = 0;
-    static int already_done;
-
-    if (already_done) {
-      return -1;
-    }
-    already_done = 1;
-    if (!(child = fork())) {
-        /*
-         * Child process.
-         */
-        zap_stdio();
-        char *exec_args[100];
-        size_t num_process_args = nargs;
-
-        memset(exec_args, 0, sizeof(exec_args));
-        if (num_process_args > ARRAY_SIZE(exec_args) - 1) {
-            ERROR("exec called with %zu args, limit is %zu", num_process_args,
-                  ARRAY_SIZE(exec_args) - 1);
-            _exit(1);
-        }
-        for (size_t i = 1; i < num_process_args; i++)
-            exec_args[i - 1] = args[i];
-
-        if (execv(exec_args[0], exec_args) == -1) {
-            ERROR("Failed to execv '%s' (%s)", exec_args[0], strerror(errno));
-            _exit(1);
-        }
-        ERROR("Returned from execv()!");
-        _exit(1);
-    }
-
-    /*
-     * Parent process.
-     */
-    if (child == -1) {
-        ERROR("Fork failed\n");
-        return -1;
-    }
-
-    if (TEMP_FAILURE_RETRY(waitpid(child, &child_status, 0)) == -1) {
-        ERROR("waitpid(): failed (%s)\n", strerror(errno));
-        return -1;
-    }
-
-    if (WIFSIGNALED(child_status)) {
-        INFO("Child exited due to signal %d\n", WTERMSIG(child_status));
-        return -1;
-    } else if (WIFEXITED(child_status)) {
-        INFO("Child exited normally (exit code %d)\n", WEXITSTATUS(child_status));
-        return WEXITSTATUS(child_status);
-    }
-
-    ERROR("Abnormal child process exit\n");
-
-    return -1;
-}
-
 int do_export(int nargs, char **args)
 {
     return add_environment(args[1], args[2]);
@@ -723,8 +661,9 @@
     return rc;
 }
 
-static void verity_update_property(fstab_rec *fstab, const char *mount_point, int status) {
-    property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(), "1");
+static void verity_update_property(fstab_rec *fstab, const char *mount_point, int mode, int status) {
+    property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(),
+                 android::base::StringPrintf("%d", mode).c_str());
 }
 
 int do_verity_update_state(int nargs, char** args) {
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 593f0c5..ff31093 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -138,7 +138,6 @@
     case 'e':
         if (!strcmp(s, "nable")) return K_enable;
         if (!strcmp(s, "xec")) return K_exec;
-        if (!strcmp(s, "xeconce")) return K_execonce;
         if (!strcmp(s, "xport")) return K_export;
         break;
     case 'g':
@@ -947,7 +946,14 @@
     for (i = 1; i < nargs; i++) {
         if (!(i % 2)) {
             if (strcmp(args[i], "&&")) {
+                struct listnode *node;
+                struct listnode *node2;
                 parse_error(state, "& is the only symbol allowed to concatenate actions\n");
+                list_for_each_safe(node, node2, &act->triggers) {
+                    struct trigger *trigger = node_to_item(node, struct trigger, nlist);
+                    free(trigger);
+                }
+                free(act);
                 return 0;
             } else
                 continue;
diff --git a/init/keywords.h b/init/keywords.h
index 4bd0ba6..059dde1 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -6,7 +6,6 @@
 int do_domainname(int nargs, char **args);
 int do_enable(int nargs, char **args);
 int do_exec(int nargs, char **args);
-int do_execonce(int nargs, char **args);
 int do_export(int nargs, char **args);
 int do_hostname(int nargs, char **args);
 int do_ifup(int nargs, char **args);
@@ -55,7 +54,6 @@
     KEYWORD(domainname,  COMMAND, 1, do_domainname)
     KEYWORD(enable,      COMMAND, 1, do_enable)
     KEYWORD(exec,        COMMAND, 1, do_exec)
-    KEYWORD(execonce,    COMMAND, 1, do_execonce)
     KEYWORD(export,      COMMAND, 2, do_export)
     KEYWORD(group,       OPTION,  0, 0)
     KEYWORD(hostname,    COMMAND, 1, do_hostname)
diff --git a/init/readme.txt b/init/readme.txt
index 630dd03..84afd11 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -182,10 +182,6 @@
    groups can be provided. No other commands will be run until this one
    finishes.
 
-execonce <path> [ <argument> ]*
-   Use exec instead. This command will be removed after existing callers have
-   moved to exec.
-
 export <name> <value>
    Set the environment variable <name> equal to <value> in the
    global environment (which will be inherited by all processes
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index b7190e2..fd1f4da 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE 1
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
@@ -73,6 +74,16 @@
   return UnwindFromContext(num_ignore_frames, nullptr);
 }
 
+bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) {
+  if (BacktraceMap::IsValid(frame.map)) {
+    const std::string library = basename(frame.map.name.c_str());
+    if (library == "libunwind.so" || library == "libbacktrace.so") {
+      return true;
+    }
+  }
+  return false;
+}
+
 static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static void SignalHandler(int, siginfo_t*, void* sigcontext) {
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
index 81ea81d..8aad36d 100644
--- a/libbacktrace/BacktraceCurrent.h
+++ b/libbacktrace/BacktraceCurrent.h
@@ -46,6 +46,9 @@
 
   bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
 
+protected:
+  bool DiscardFrame(const backtrace_frame_data_t& frame);
+
 private:
   bool UnwindThread(size_t num_ignore_frames);
 
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 12e2890..67e583f 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -99,25 +99,30 @@
       break;
     }
 
-    if (num_ignore_frames == 0) {
-      frames_.resize(num_frames+1);
-      backtrace_frame_data_t* frame = &frames_.at(num_frames);
-      frame->num = num_frames;
-      frame->pc = static_cast<uintptr_t>(pc);
-      frame->sp = static_cast<uintptr_t>(sp);
-      frame->stack_size = 0;
+    frames_.resize(num_frames+1);
+    backtrace_frame_data_t* frame = &frames_.at(num_frames);
+    frame->num = num_frames;
+    frame->pc = static_cast<uintptr_t>(pc);
+    frame->sp = static_cast<uintptr_t>(sp);
+    frame->stack_size = 0;
 
-      if (num_frames > 0) {
-        // Set the stack size for the previous frame.
-        backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
-        prev->stack_size = frame->sp - prev->sp;
+    FillInMap(frame->pc, &frame->map);
+    // Check to see if we should skip this frame because it's coming
+    // from within the library, and we are doing a local unwind.
+    if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
+      if (num_ignore_frames == 0) {
+        // GetFunctionName is an expensive call, only do it if we are
+        // keeping the frame.
+        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+        if (num_frames > 0) {
+          // Set the stack size for the previous frame.
+          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
+          prev->stack_size = frame->sp - prev->sp;
+        }
+        num_frames++;
+      } else {
+        num_ignore_frames--;
       }
-
-      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
-      FillInMap(frame->pc, &frame->map);
-      num_frames++;
-    } else {
-      num_ignore_frames--;
     }
     ret = unw_step (cursor.get());
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index d408856..4af6592 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE 1
 #include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
@@ -86,7 +87,7 @@
 
 std::string DumpFrames(Backtrace* backtrace) {
   if (backtrace->NumFrames() == 0) {
-    return "   No frames to dump\n";
+    return "   No frames to dump.\n";
   }
 
   std::string frame;
@@ -123,8 +124,10 @@
 }
 
 void VerifyLevelDump(Backtrace* backtrace) {
-  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0));
-  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
+    << DumpFrames(backtrace);
+  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
 
   // Look through the frames starting at the highest to find the
   // frame we want.
@@ -138,10 +141,14 @@
   ASSERT_LT(static_cast<size_t>(0), frame_num) << DumpFrames(backtrace);
   ASSERT_LE(static_cast<size_t>(3), frame_num) << DumpFrames(backtrace);
 
-  ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four");
+  ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four")
+    << DumpFrames(backtrace);
 }
 
 void VerifyLevelBacktrace(void*) {
@@ -158,10 +165,11 @@
 }
 
 void VerifyMaxDump(Backtrace* backtrace) {
-  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
   // Verify that the last frame is our recursive call.
-  ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name,
-            "test_recursive_call");
+  ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, "test_recursive_call")
+    << DumpFrames(backtrace);
 }
 
 void VerifyMaxBacktrace(void*) {
@@ -200,6 +208,24 @@
   return false;
 }
 
+TEST(libbacktrace, local_no_unwind_frames) {
+  // Verify that a local unwind does not include any frames within
+  // libunwind or libbacktrace.
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_TRUE(backtrace->Unwind(0));
+
+  ASSERT_TRUE(backtrace->NumFrames() != 0);
+  for (const auto& frame : *backtrace ) {
+    if (BacktraceMap::IsValid(frame.map)) {
+      const std::string name = basename(frame.map.name.c_str());
+      ASSERT_TRUE(name != "libunwind.so" && name != "libbacktrace.so")
+        << DumpFrames(backtrace.get());
+    }
+    break;
+  }
+}
+
 TEST(libbacktrace, local_trace) {
   ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
 }
@@ -207,8 +233,10 @@
 void VerifyIgnoreFrames(
     Backtrace* bt_all, Backtrace* bt_ign1,
     Backtrace* bt_ign2, const char* cur_proc) {
-  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1);
-  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2);
+  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1)
+    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1);
+  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2)
+    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2);
 
   // Check all of the frames are the same > the current frame.
   bool check = (cur_proc == nullptr);
@@ -266,6 +294,7 @@
   }
   uint64_t start = NanoTime();
   bool verified = false;
+  std::string last_dump;
   do {
     usleep(US_PER_MSEC);
     if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
@@ -277,18 +306,20 @@
         map.reset(BacktraceMap::Create(pid));
       }
       std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
-      ASSERT_TRUE(backtrace->Unwind(0));
       ASSERT_TRUE(backtrace.get() != nullptr);
+      ASSERT_TRUE(backtrace->Unwind(0));
       if (ReadyFunc(backtrace.get())) {
         VerifyFunc(backtrace.get());
         verified = true;
+      } else {
+        last_dump = DumpFrames(backtrace.get());
       }
 
       ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
     }
     // If 5 seconds have passed, then we are done.
   } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
-  ASSERT_TRUE(verified);
+  ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
 }
 
 TEST(libbacktrace, ptrace_trace) {
@@ -680,16 +711,19 @@
   BacktraceMap* map3 = BacktraceMap::Create(getpid());
 
   Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
+  ASSERT_TRUE(back1 != nullptr);
   EXPECT_TRUE(back1->Unwind(0));
   delete back1;
   delete map1;
 
   Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
+  ASSERT_TRUE(back2 != nullptr);
   EXPECT_TRUE(back2->Unwind(0));
   delete back2;
   delete map2;
 
   Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
+  ASSERT_TRUE(back3 != nullptr);
   EXPECT_TRUE(back3->Unwind(0));
   delete back3;
   delete map3;
@@ -971,6 +1005,7 @@
       WaitForStop(pid);
 
       std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+      ASSERT_TRUE(backtrace.get() != nullptr);
 
       uintptr_t read_addr;
       size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready),
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 9f32307..c636196 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -22,6 +22,7 @@
 	native_handle.c \
 	config_utils.c \
 	load_file.c \
+	strlcpy.c \
 	open_memstream.c \
 	strdup16to8.c \
 	strdup8to16.c \
@@ -31,6 +32,7 @@
 	sched_policy.c \
 	iosched_policy.c \
 	str_parms.c \
+	fs_config.c
 
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
@@ -74,7 +76,6 @@
 LOCAL_CFLAGS += -Werror
 endif
 LOCAL_MULTILIB := both
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -85,22 +86,8 @@
 LOCAL_CFLAGS += -Werror
 endif
 LOCAL_MULTILIB := both
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_SHARED_LIBRARY)
 
-# Tests for host
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS
-ifneq ($(HOST_OS),windows)
-LOCAL_CFLAGS += -Werror
-endif
-LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_HOST_EXECUTABLE)
 
 
 # Shared and static library for target
@@ -113,32 +100,19 @@
         ashmem-dev.c \
         debugger.c \
         klog.c \
-        memory.c \
         partition_utils.c \
         properties.c \
         qtaguid.c \
         trace-dev.c \
         uevent.c \
 
-LOCAL_SRC_FILES_arm += \
-        arch-arm/memset32.S \
-
 # arch-arm/memset32.S does not compile with Clang.
 LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
 
-LOCAL_SRC_FILES_arm64 += \
-        arch-arm64/android_memset.S \
-
-ifndef ARCH_MIPS_REV6
-LOCAL_SRC_FILES_mips += \
-        arch-mips/android_memset.c \
-
-LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-endif
-
-# TODO: switch mips64 back to using arch-mips/android_memset.c
-LOCAL_SRC_FILES_mips64 += \
-#       arch-mips/android_memset.c \
+LOCAL_SRC_FILES_arm += arch-arm/memset32.S
+LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
+LOCAL_SRC_FILES_mips += arch-mips/android_memset.S
+LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.S
 
 LOCAL_SRC_FILES_x86 += \
         arch-x86/android_memset16.S \
@@ -148,16 +122,9 @@
         arch-x86_64/android_memset16.S \
         arch-x86_64/android_memset32.S \
 
-LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-#LOCAL_CFLAGS_mips64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += -Werror -std=gnu90
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -168,16 +135,6 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_CFLAGS += -Werror
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror
-LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_EXECUTABLE)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/arch-mips/android_memset.S b/libcutils/arch-mips/android_memset.S
new file mode 100644
index 0000000..6811de0
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.S
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2009
+ *      MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/************************************************************************
+ *
+ *  memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
+ *  Version: "043009"
+ *
+ ************************************************************************/
+
+
+/************************************************************************
+ *  Include files
+ ************************************************************************/
+
+#include <machine/asm.h>
+#define END(f) .cfi_endproc; .size f, .-f; .end f
+
+/*
+ * This routine could be optimized for MIPS64. The current code only
+ * uses MIPS32 instructions.
+ */
+
+#if defined(__MIPSEB__)
+#  define SWHI	swl		/* high part is left in big-endian	*/
+#  define SWLO	swr		/* low part is right in big-endian	*/
+#endif
+
+#if defined(__MIPSEL__)
+#  define SWHI	swr		/* high part is right in little-endian	*/
+#  define SWLO	swl		/* low part is left in little-endian	*/
+#endif
+
+#if !(defined(XGPROF) || defined(XPROF))
+#undef SETUP_GP
+#define SETUP_GP
+#endif
+
+#ifdef NDEBUG
+#define DBG #
+#else
+#define DBG
+#endif
+
+/*
+ * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
+ */
+
+LEAF(android_memset16,0)
+	.set noreorder
+DBG	/* Check parameters */
+DBG	andi	t0,a0,1			# a0 must be halfword aligned
+DBG	tne	t0,zero
+DBG	andi	t2,a2,1			# a2 must be even
+DBG	tne	t2,zero
+
+#ifdef FIXARGS
+	# ensure count is even
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	a2,zero,0,1
+#else
+	ori	a2,1
+	xori	a2,1
+#endif
+#endif
+
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	a1,a1,16,16
+#else
+	andi	a1,0xffff
+	sll	t3,a1,16
+	or	a1,t3
+#endif
+
+	beqz	a2,.Ldone
+	 andi	t1,a0,2
+	beqz	t1,.Lalignok
+	 addu	t0,a0,a2		# t0 is the "past the end" address
+	sh	a1,0(a0)		# store one halfword to get aligned
+	addu	a0,2
+	subu	a2,2
+.Lalignok:
+	slti	t1,a2,4			# .Laligned for 4 or more bytes
+	beqz	t1,.Laligned
+	 sne	t1,a2,2			# one more halfword?
+	bnez	t1,.Ldone
+	 nop
+	sh	a1,0(a0)
+.Ldone:
+	j	ra
+	 nop
+	.set reorder
+END(android_memset16)
+
+/*
+ * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
+ */
+
+LEAF(android_memset32,0)
+	.set noreorder
+DBG	/* Check parameters */
+DBG	andi	t0,a0,3			# a0 must be word aligned
+DBG	tne	t0,zero
+DBG	andi	t2,a2,3			# a2 must be a multiple of 4 bytes
+DBG	tne	t2,zero
+
+#ifdef FIXARGS
+	# ensure count is a multiple of 4
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	$a2,$0,0,2
+#else
+	ori	a2,3
+	xori	a2,3
+#endif
+#endif
+
+	bnez	a2,.Laligned		# any work to do?
+	 addu	t0,a0,a2		# t0 is the "past the end" address
+
+	j	ra
+	 nop
+	.set reorder
+END(android_memset32)
+
+LEAF(memset,0)
+
+	.set	noreorder
+	.set	noat
+
+	addu	t0,a0,a2		# t0 is the "past the end" address
+	slti	AT,a2,4			# is a2 less than 4?
+	bne	AT,zero,.Llast4		# if yes, go to last4
+	 move	v0,a0			# memset returns the dst pointer
+
+	beq	a1,zero,.Lset0
+	 subu	v1,zero,a0
+
+	# smear byte into 32 bit word
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins     a1, a1, 8, 8        # Replicate fill byte into half-word.
+	ins     a1, a1, 16, 16      # Replicate fill byte into word.
+#else
+	and	a1,0xff
+	sll	AT,a1,8
+	or	a1,AT
+	sll	AT,a1,16
+	or	a1,AT
+#endif
+
+.Lset0:
+	andi	v1,v1,0x3		# word-unaligned address?
+	beq	v1,zero,.Laligned	# v1 is the unalignment count
+	 subu	a2,a2,v1
+	SWHI	a1,0(a0)
+	addu	a0,a0,v1
+
+# Here we have the "word-aligned" a0 (until the "last4")
+.Laligned:
+	andi	t8,a2,0x3f	# any 64-byte chunks?
+				# t8 is the byte count past 64-byte chunks
+	beq	a2,t8,.Lchk8w	# when a2==t8, no 64-byte chunks
+				# There will be at most 1 32-byte chunk then
+	 subu	a3,a2,t8	# subtract from a2 the reminder
+				# Here a3 counts bytes in 16w chunks
+	addu	a3,a0,a3	# Now a3 is the final dst after 64-byte chunks
+
+# Find out, if there are any 64-byte chunks after which will be still at least
+# 96 bytes left. The value "96" is calculated as needed buffer for
+# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
+# incrementing "a0" by 64.
+# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
+#
+	sltiu	v1,a2,160
+	bgtz	v1,.Lloop16w_nopref30	# skip "pref 30,0(a0)"
+	 subu	t7,a2,96	# subtract "pref 30 unsafe" region
+		# below we have at least 1 64-byte chunk which is "pref 30 safe"
+	andi	t6,t7,0x3f	# t6 is past "64-byte safe chunks" reminder
+	subu	t5,t7,t6	# subtract from t7 the reminder
+				# Here t5 counts bytes in 16w "safe" chunks
+	addu	t4,a0,t5	# Now t4 is the dst after 64-byte "safe" chunks
+
+# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
+#	pref	30,0(a0)
+# Here we are in the region, where it is safe to use "pref 30,64(a0)"
+.Lloop16w:
+	addiu	a0,a0,64
+	pref	30,-32(a0)	# continue setting up the dest, addr 64-32
+	sw	a1,-64(a0)
+	sw	a1,-60(a0)
+	sw	a1,-56(a0)
+	sw	a1,-52(a0)
+	sw	a1,-48(a0)
+	sw	a1,-44(a0)
+	sw	a1,-40(a0)
+	sw	a1,-36(a0)
+	nop
+	nop			# the extra nop instructions help to balance
+	nop			# cycles needed for "store" + "fill" + "evict"
+	nop			# For 64byte store there are needed 8 fill
+	nop			# and 8 evict cycles, i.e. at least 32 instr.
+	nop
+	nop
+	pref	30,0(a0)	# continue setting up the dest, addr 64-0
+	sw	a1,-32(a0)
+	sw	a1,-28(a0)
+	sw	a1,-24(a0)
+	sw	a1,-20(a0)
+	sw	a1,-16(a0)
+	sw	a1,-12(a0)
+	sw	a1,-8(a0)
+	sw	a1,-4(a0)
+	nop
+	nop
+	nop
+	nop			# NOTE: adding 14 nop-s instead of 12 nop-s
+	nop			# gives better results for "fast" memory
+	nop
+	bne	a0,t4,.Lloop16w
+	 nop
+
+	beq	a0,a3,.Lchk8w	# maybe no more 64-byte chunks?
+	 nop			# this "delayed slot" is useless ...
+
+.Lloop16w_nopref30:	# there could be up to 3 "64-byte nopref30" chunks
+	addiu	a0,a0,64
+	sw	a1,-64(a0)
+	sw	a1,-60(a0)
+	sw	a1,-56(a0)
+	sw	a1,-52(a0)
+	sw	a1,-48(a0)
+	sw	a1,-44(a0)
+	sw	a1,-40(a0)
+	sw	a1,-36(a0)
+	sw	a1,-32(a0)
+	sw	a1,-28(a0)
+	sw	a1,-24(a0)
+	sw	a1,-20(a0)
+	sw	a1,-16(a0)
+	sw	a1,-12(a0)
+	sw	a1,-8(a0)
+	bne	a0,a3,.Lloop16w_nopref30
+	 sw	a1,-4(a0)
+
+.Lchk8w:		# t8 here is the byte count past 64-byte chunks
+
+	andi	t7,t8,0x1f	# is there a 32-byte chunk?
+				# the t7 is the reminder count past 32-bytes
+	beq	t8,t7,.Lchk1w	# when t8==t7, no 32-byte chunk
+	 move	a2,t7
+
+	sw	a1,0(a0)
+	sw	a1,4(a0)
+	sw	a1,8(a0)
+	sw	a1,12(a0)
+	sw	a1,16(a0)
+	sw	a1,20(a0)
+	sw	a1,24(a0)
+	sw	a1,28(a0)
+	addiu	a0,a0,32
+
+.Lchk1w:
+	andi	t8,a2,0x3	# now t8 is the reminder past 1w chunks
+	beq	a2,t8,.Llast4aligned
+	 subu	a3,a2,t8	# a3 is the count of bytes in 1w chunks
+	addu	a3,a0,a3	# now a3 is the dst address past the 1w chunks
+
+# copying in words (4-byte chunks)
+.LwordCopy_loop:
+	addiu	a0,a0,4
+	bne	a0,a3,.LwordCopy_loop
+	 sw	a1,-4(a0)
+
+# store last 0-3 bytes
+# this will repeat the last store if the memset finishes on a word boundary
+.Llast4aligned:
+	j	ra
+	 SWLO	a1,-1(t0)
+
+.Llast4:
+	beq	a0,t0,.Llast4e
+.Llast4l:
+	 addiu	a0,a0,1
+	bne	a0,t0,.Llast4l
+	 sb	a1,-1(a0)
+.Llast4e:
+	j	ra
+	 nop
+
+	.set	at
+	.set	reorder
+
+END(memset)
+
+
+/************************************************************************
+ *  Implementation : Static functions
+ ************************************************************************/
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
deleted file mode 100644
index bbc99fe..0000000
--- a/libcutils/arch-mips/android_memset.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cutils/memory.h>
-
-/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */
-void _memset16(uint16_t* dst, uint16_t value, size_t size);
-void _memset32(uint32_t* dst, uint32_t value, size_t size);
-
-void android_memset16(uint16_t* dst, uint16_t value, size_t size)
-{
-    _memset16(dst, value, size);
-}
-
-void android_memset32(uint32_t* dst, uint32_t value, size_t size)
-{
-    _memset32(dst, value, size);
-}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
new file mode 100644
index 0000000..659f614
--- /dev/null
+++ b/libcutils/fs_config.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This file is used to define the properties of the filesystem
+** images generated by build tools (mkbootfs and mkyaffs2image) and
+** by the device side of adb.
+*/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <private/android_filesystem_config.h>
+
+/* Rules for directories.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root.
+*/
+
+static const struct fs_path_config android_dirs[] = {
+    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
+    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
+    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
+    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
+    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
+};
+
+/* Rules for files.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root. Prefixes ending in * denotes wildcard
+** and will allow partial matches.
+*/
+static const struct fs_path_config android_files[] = {
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
+    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
+    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+
+    /* the following five files are INTENTIONALLY set-uid, but they
+     * are NOT included on user builds. */
+    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
+    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+
+    /* the following files have enhanced capabilities and ARE included in user builds. */
+    { 00750, AID_ROOT,      AID_SHELL,     (1ULL << CAP_SETUID) | (1ULL << CAP_SETGID), "system/bin/run-as" },
+    { 00700, AID_SYSTEM,    AID_SHELL,     (1ULL << CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
+    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
+};
+
+void fs_config(const char *path, int dir,
+               unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
+{
+    const struct fs_path_config *pc;
+    int plen;
+
+    if (path[0] == '/') {
+        path++;
+    }
+
+    pc = dir ? android_dirs : android_files;
+    plen = strlen(path);
+    for(; pc->prefix; pc++){
+        int len = strlen(pc->prefix);
+        if (dir) {
+            if(plen < len) continue;
+            if(!strncmp(pc->prefix, path, len)) break;
+            continue;
+        }
+        /* If name ends in * then allow partial matches. */
+        if (pc->prefix[len -1] == '*') {
+            if(!strncmp(pc->prefix, path, len - 1)) break;
+        } else if (plen == len){
+            if(!strncmp(pc->prefix, path, len)) break;
+        }
+    }
+    *uid = pc->uid;
+    *gid = pc->gid;
+    *mode = (*mode & (~07777)) | pc->mode;
+    *capabilities = pc->capabilities;
+}
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index a6da9ca..8946d3c 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -1,5 +1,5 @@
 /*
-** Copyright 2007-2014, The Android Open Source Project
+** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
 ** you may not use this file except in compliance with the License. 
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index dfe8c4b..924289a 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -357,51 +357,3 @@
 {
     hashmapForEach(str_parms->map, dump_entry, str_parms);
 }
-
-#ifdef TEST_STR_PARMS
-static void test_str_parms_str(const char *str)
-{
-    struct str_parms *str_parms;
-    char *out_str;
-
-    str_parms = str_parms_create_str(str);
-    str_parms_add_str(str_parms, "dude", "woah");
-    str_parms_add_str(str_parms, "dude", "woah");
-    str_parms_del(str_parms, "dude");
-    str_parms_dump(str_parms);
-    out_str = str_parms_to_str(str_parms);
-    str_parms_destroy(str_parms);
-    ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
-    free(out_str);
-}
-
-int main(void)
-{
-    test_str_parms_str("");
-    test_str_parms_str(";");
-    test_str_parms_str("=");
-    test_str_parms_str("=;");
-    test_str_parms_str("=bar");
-    test_str_parms_str("=bar;");
-    test_str_parms_str("foo=");
-    test_str_parms_str("foo=;");
-    test_str_parms_str("foo=bar");
-    test_str_parms_str("foo=bar;");
-    test_str_parms_str("foo=bar;baz");
-    test_str_parms_str("foo=bar;baz=");
-    test_str_parms_str("foo=bar;baz=bat");
-    test_str_parms_str("foo=bar;baz=bat;");
-    test_str_parms_str("foo=bar;baz=bat;foo=bar");
-
-    // hashmapPut reports errors by setting errno to ENOMEM.
-    // Test that we're not confused by running in an environment where this is already true.
-    errno = ENOMEM;
-    test_str_parms_str("foo=bar;baz=");
-    if (errno != ENOMEM) {
-        abort();
-    }
-    test_str_parms_str("foo=bar;baz=");
-
-    return 0;
-}
-#endif
diff --git a/libcutils/memory.c b/libcutils/strlcpy.c
similarity index 62%
rename from libcutils/memory.c
rename to libcutils/strlcpy.c
index 6486b45..c66246c 100644
--- a/libcutils/memory.c
+++ b/libcutils/strlcpy.c
@@ -1,43 +1,4 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cutils/memory.h>
-
-#if !HAVE_MEMSET16
-void android_memset16(uint16_t* dst, uint16_t value, size_t size)
-{
-    size >>= 1;
-    while (size--) {
-        *dst++ = value;
-    }
-}
-#endif
-
-#if !HAVE_MEMSET32
-void android_memset32(uint32_t* dst, uint32_t value, size_t size)
-{
-    size >>= 2;
-    while (size--) {
-        *dst++ = value;
-    }
-}
-#endif
-
-#if !HAVE_STRLCPY
-/*
  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -54,8 +15,13 @@
  */
 
 #include <sys/types.h>
+
+#if defined(__GLIBC__) || defined(_WIN32)
+
 #include <string.h>
 
+#include <cutils/memory.h>
+
 /* Implementation of strlcpy() for platforms that don't already have it. */
 
 /*
@@ -88,4 +54,5 @@
 
 	return(s - src - 1);	/* count does not include NUL */
 }
+
 #endif
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
index 5a54698..cf70345 100644
--- a/libcutils/tests/Android.mk
+++ b/libcutils/tests/Android.mk
@@ -15,38 +15,59 @@
 LOCAL_PATH := $(call my-dir)
 
 test_src_files := \
+    test_str_parms.cpp \
+
+test_target_only_src_files := \
     MemsetTest.cpp \
     PropertiesTest.cpp \
 
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libutils \
+test_libraries := libcutils liblog
 
+
+#
+# Target.
+#
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
+LOCAL_SHARED_LIBRARIES := $(test_libraries)
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 include $(BUILD_NATIVE_TEST)
 
-# The static libcutils tests cannot be built when using libc++ because there are
-# multiple symbol definition errors between libc++ and libgcc. b/18389856
-#include $(CLEAR_VARS)
-#LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-#LOCAL_MODULE := libcutils_test_static
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-#LOCAL_SRC_FILES := $(test_src_files)
-#LOCAL_STATIC_LIBRARIES := \
-#    libc \
-#    libcutils \
-#    liblog \
-#    libutils \
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
+LOCAL_STATIC_LIBRARIES := libc $(test_libraries)
+LOCAL_CXX_STL := libc++_static
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
 
-#LOCAL_CXX_STL := stlport_static
-#LOCAL_MULTILIB := both
-#LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-#LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-#include $(BUILD_NATIVE_TEST)
+
+#
+# Host.
+#
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := $(test_libraries)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_HOST_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES := $(test_libraries)
+LOCAL_CXX_STL := libc++_static
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcutils/tests/test_str_parms.cpp b/libcutils/tests/test_str_parms.cpp
new file mode 100644
index 0000000..d8f639b
--- /dev/null
+++ b/libcutils/tests/test_str_parms.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/str_parms.h>
+#include <gtest/gtest.h>
+
+static void test_str_parms_str(const char* str, const char* expected) {
+    str_parms* str_parms = str_parms_create_str(str);
+    str_parms_add_str(str_parms, "dude", "woah");
+    str_parms_add_str(str_parms, "dude", "woah");
+    str_parms_del(str_parms, "dude");
+    str_parms_dump(str_parms);
+    char* out_str = str_parms_to_str(str_parms);
+    str_parms_destroy(str_parms);
+    ASSERT_STREQ(expected, out_str) << str;
+    free(out_str);
+}
+
+TEST(str_parms, smoke) {
+    test_str_parms_str("", "");
+    test_str_parms_str(";", "");
+    test_str_parms_str("=", "");
+    test_str_parms_str("=;", "");
+    test_str_parms_str("=bar", "");
+    test_str_parms_str("=bar;", "");
+    test_str_parms_str("foo=", "foo=");
+    test_str_parms_str("foo=;", "foo=");
+    test_str_parms_str("foo=bar", "foo=bar");
+    test_str_parms_str("foo=bar;", "foo=bar");
+    test_str_parms_str("foo=bar;baz", "foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=bat", "foo=bar;baz=bat");
+    test_str_parms_str("foo=bar;baz=bat;", "foo=bar;baz=bat");
+    test_str_parms_str("foo=bar1;baz=bat;foo=bar2", "foo=bar2;baz=bat");
+}
+
+TEST(str_parms, put_ENOMEM) {
+    // hashmapPut reports errors by setting errno to ENOMEM.
+    // Test that we're not confused by running in an environment where this is already true.
+    errno = ENOMEM;
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+    ASSERT_EQ(ENOMEM, errno);
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+}
diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk
index abf527a..894f90e 100644
--- a/libion/tests/Android.mk
+++ b/libion/tests/Android.mk
@@ -18,7 +18,6 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := ion-unit-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
 LOCAL_SHARED_LIBRARIES += libion
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index dfe34d1..c62a246 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -356,43 +356,7 @@
 
 int __android_log_write(int prio, const char *tag, const char *msg)
 {
-    struct iovec vec[3];
-    log_id_t log_id = LOG_ID_MAIN;
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS")) {
-            log_id = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-#if __BIONIC__
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-#endif
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(log_id, vec, 3);
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -420,6 +384,12 @@
             tag = tmp_tag;
     }
 
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+#endif
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index ca63067..8742b34 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -139,41 +139,7 @@
 
 int __android_log_write(int prio, const char *tag, const char *msg)
 {
-    struct iovec vec[3];
-    log_id_t log_id = LOG_ID_MAIN;
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS")) {
-            log_id = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(log_id, vec, 3);
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -201,6 +167,10 @@
             tag = tmp_tag;
     }
 
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 8137a75..d75bbc9 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -39,7 +39,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(benchmark_c_flags)
 LOCAL_SHARED_LIBRARIES += liblog libm
 LOCAL_SRC_FILES := $(benchmark_src_files)
@@ -77,7 +76,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk
index 9c9562a..8137c7a 100644
--- a/libsync/tests/Android.mk
+++ b/libsync/tests/Android.mk
@@ -19,7 +19,6 @@
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
 LOCAL_MODULE := sync-unit-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare
 LOCAL_SHARED_LIBRARIES += libsync
 LOCAL_STATIC_LIBRARIES += libgtest_main
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index 634f44f..7cfad89 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -18,7 +18,6 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := libutils_tests
 
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index 3937449..a3087ee 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -18,21 +18,19 @@
 source_files := zip_archive.cc
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
 LOCAL_STATIC_LIBRARIES := libz
-LOCAL_SHARED_LIBRARIES := libutils
+LOCAL_SHARED_LIBRARIES := libutils libbase
 LOCAL_MODULE:= libziparchive
 LOCAL_CFLAGS := -Werror -Wall
 LOCAL_CPPFLAGS := -Wold-style-cast
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
-LOCAL_STATIC_LIBRARIES := libz libutils
+LOCAL_STATIC_LIBRARIES := libz libutils libbase
 LOCAL_MODULE:= libziparchive-host
 LOCAL_CFLAGS := -Werror
 ifneq ($(strip $(USE_MINGW)),)
@@ -42,11 +40,10 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
 LOCAL_STATIC_LIBRARIES := libz libutils
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_MODULE:= libziparchive-host
 LOCAL_CFLAGS := -Werror
 LOCAL_MULTILIB := both
@@ -54,24 +51,22 @@
 
 # Tests.
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_MODULE := ziparchive-tests
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS := -Werror
 LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_STATIC_LIBRARIES := libziparchive libz libutils
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_MODULE := ziparchive-tests-host
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS += \
     -Werror \
     -Wno-unnamed-type-template-args
 LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc
-LOCAL_SHARED_LIBRARIES := libziparchive-host liblog
+LOCAL_SHARED_LIBRARIES := libziparchive-host liblog libbase
 LOCAL_STATIC_LIBRARIES := \
     libz \
     libutils
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 58285f1..57c46a3 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,27 +18,29 @@
  * Read-only access to Zip archives, with minimal heap allocation.
  */
 
-#include <memory>
-#include <vector>
-
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <log/log.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <utils/Compat.h>
-#include <utils/FileMap.h>
-#include <zlib.h>
 
-#include <JNIHelp.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
+#include "base/memory.h"
+#include "log/log.h"
+#include "utils/Compat.h"
+#include "utils/FileMap.h"
+#include "zlib.h"
 
 #include "entry_name_utils-inl.h"
 #include "ziparchive/zip_archive.h"
 
+using android::base::get_unaligned;
 
 // This is for windows. If we don't open a file in binary mode, weird
 // things will happen.
@@ -46,11 +48,6 @@
 #define O_BINARY 0
 #endif
 
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-    TypeName(); \
-    TypeName(const TypeName&); \
-    void operator=(const TypeName&)
-
 // The "end of central directory" (EOCD) record. Each archive
 // contains exactly once such record which appears at the end of
 // the archive. It contains archive wide information like the
@@ -462,10 +459,12 @@
    */
   int i = read_amount - sizeof(EocdRecord);
   for (; i >= 0; i--) {
-    if (scan_buffer[i] == 0x50 &&
-        ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
-      ALOGV("+++ Found EOCD at buf+%d", i);
-      break;
+    if (scan_buffer[i] == 0x50) {
+      uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
+      if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
+        ALOGV("+++ Found EOCD at buf+%d", i);
+        break;
+      }
     }
   }
   if (i < 0) {
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index be96fc4..2b19b93 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -12,6 +12,7 @@
 #include <signal.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/cdefs.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <arpa/inet.h>
@@ -24,7 +25,6 @@
 #include <log/logprint.h>
 #include <log/event_tag_map.h>
 
-#define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
 #define DEFAULT_MAX_ROTATED_LOGS 4
 
 static AndroidLogFormat * g_logformat;
@@ -46,6 +46,8 @@
         binary = b;
         next = NULL;
         printed = false;
+        logger = NULL;
+        logger_list = NULL;
     }
 };
 
@@ -54,13 +56,17 @@
 /* Global Variables */
 
 static const char * g_outputFileName = NULL;
-static int g_logRotateSizeKBytes = 0;                   // 0 means "no log rotation"
-static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
+// 0 means "no log rotation"
+static size_t g_logRotateSizeKBytes = 0;
+// 0 means "unbounded"
+static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
 static int g_outFD = -1;
-static off_t g_outByteCount = 0;
+static size_t g_outByteCount = 0;
 static int g_printBinary = 0;
 static int g_devCount = 0;                              // >1 means multiple
 
+__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
+
 static int openLogFile (const char *pathname)
 {
     return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
@@ -93,7 +99,12 @@
             asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
         }
 
-        err = rename (file0, file1);
+        if (!file0 || !file1) {
+            perror("while rotating log files");
+            break;
+        }
+
+        err = rename(file0, file1);
 
         if (err < 0 && errno != ENOENT) {
             perror("while rotating log files");
@@ -103,11 +114,10 @@
         free(file0);
     }
 
-    g_outFD = openLogFile (g_outputFileName);
+    g_outFD = openLogFile(g_outputFileName);
 
     if (g_outFD < 0) {
-        perror ("couldn't open output file");
-        exit(-1);
+        logcat_panic(false, "couldn't open output file");
     }
 
     g_outByteCount = 0;
@@ -153,8 +163,7 @@
         bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
 
         if (bytesWritten < 0) {
-            perror("output error");
-            exit(-1);
+            logcat_panic(false, "output error");
         }
     }
 
@@ -179,8 +188,7 @@
                      dev->printed ? "switch to" : "beginning of",
                      dev->device);
             if (write(g_outFD, buf, strlen(buf)) < 0) {
-                perror("output error");
-                exit(-1);
+                logcat_panic(false, "output error");
             }
         }
         dev->printed = true;
@@ -199,11 +207,18 @@
         g_outFD = openLogFile (g_outputFileName);
 
         if (g_outFD < 0) {
-            perror ("couldn't open output file");
-            exit(-1);
+            logcat_panic(false, "couldn't open output file");
         }
 
-        fstat(g_outFD, &statbuf);
+        if (fstat(g_outFD, &statbuf) == -1) {
+            close(g_outFD);
+            logcat_panic(false, "couldn't get output file stat\n");
+        }
+
+        if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
+            close(g_outFD);
+            logcat_panic(false, "invalid output file stat\n");
+        }
 
         g_outByteCount = statbuf.st_size;
     }
@@ -217,7 +232,7 @@
                     "  -s              Set default filter to silent.\n"
                     "                  Like specifying filterspec '*:S'\n"
                     "  -f <filename>   Log to file. Default to stdout\n"
-                    "  -r [<kbytes>]   Rotate log every kbytes. (16 if unspecified). Requires -f\n"
+                    "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
                     "  -v <format>     Sets the log print format, where <format> is:\n\n"
                     "                  brief color long process raw tag thread threadtime time\n\n"
@@ -265,9 +280,6 @@
                    "or defaults to \"threadtime\"\n\n");
 }
 
-
-} /* namespace android */
-
 static int setLogFormat(const char * formatString)
 {
     static AndroidLogPrintFormat format;
@@ -308,8 +320,46 @@
     return multipliers[i];
 }
 
+/*String to unsigned int, returns -1 if it fails*/
+static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
+                        size_t max = SIZE_MAX)
+{
+    char *endp;
+    errno = 0;
+    size_t ret = (size_t) strtoll(ptr, &endp, 0);
+
+    if (endp[0] != '\0' || errno != 0 ) {
+        return false;
+    }
+
+    if (ret >  max || ret <  min) {
+        return false;
+    }
+
+    *val = ret;
+    return true;
+}
+
+static void logcat_panic(bool showHelp, const char *fmt, ...)
+{
+    va_list  args;
+    va_start(args, fmt);
+    vfprintf(stderr, fmt,  args);
+    va_end(args);
+
+    if (showHelp) {
+       show_help(getprogname());
+    }
+
+    exit(EXIT_FAILURE);
+}
+
+} /* namespace android */
+
+
 int main(int argc, char **argv)
 {
+    using namespace android;
     int err;
     int hasSetLogFormat = 0;
     int clearLog = 0;
@@ -324,7 +374,7 @@
     log_device_t* dev;
     bool printDividers = false;
     struct logger_list *logger_list;
-    unsigned int tail_lines = 0;
+    size_t tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
 
     signal(SIGPIPE, exit);
@@ -332,14 +382,14 @@
     g_logformat = android_log_format_new();
 
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
-        android::show_help(argv[0]);
-        exit(0);
+        show_help(argv[0]);
+        return EXIT_SUCCESS;
     }
 
     for (;;) {
         int ret;
 
-        ret = getopt(argc, argv, "cdDLt:T:gG:sQf:r:n:v:b:BSpP:");
+        ret = getopt(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:");
 
         if (ret < 0) {
             break;
@@ -372,10 +422,9 @@
                     char *cp = tail_time.strptime(optarg,
                                                   log_time::default_format);
                     if (!cp) {
-                        fprintf(stderr,
-                                "ERROR: -%c \"%s\" not in \"%s\" time format\n",
-                                ret, optarg, log_time::default_format);
-                        exit(1);
+                        logcat_panic(false,
+                                    "-%c \"%s\" not in \"%s\" time format\n",
+                                    ret, optarg, log_time::default_format);
                     }
                     if (*cp) {
                         char c = *cp;
@@ -386,8 +435,7 @@
                         *cp = c;
                     }
                 } else {
-                    tail_lines = atoi(optarg);
-                    if (!tail_lines) {
+                    if (!getSizeTArg(optarg, &tail_lines, 1)) {
                         fprintf(stderr,
                                 "WARNING: -%c %s invalid, setting to 1\n",
                                 ret, optarg);
@@ -405,13 +453,11 @@
             break;
 
             case 'G': {
-                // would use atol if not for the multiplier
-                char *cp = optarg;
-                setLogSize = 0;
-                while (('0' <= *cp) && (*cp <= '9')) {
-                    setLogSize *= 10;
-                    setLogSize += *cp - '0';
-                    ++cp;
+                char *cp;
+                if (strtoll(optarg, &cp, 0) > 0) {
+                    setLogSize = strtoll(optarg, &cp, 0);
+                } else {
+                    setLogSize = 0;
                 }
 
                 switch(*cp) {
@@ -436,7 +482,7 @@
 
                 if (!setLogSize) {
                     fprintf(stderr, "ERROR: -G <num><multiplier>\n");
-                    exit(1);
+                    return EXIT_FAILURE;
                 }
             }
             break;
@@ -458,7 +504,7 @@
                     }
 
                     devices = dev = NULL;
-                    android::g_devCount = 0;
+                    g_devCount = 0;
                     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                         const char *name = android_log_id_to_name((log_id_t)i);
                         log_id_t log_id = android_name_to_log_id(name);
@@ -476,7 +522,7 @@
                         } else {
                             devices = dev = d;
                         }
-                        android::g_devCount++;
+                        g_devCount++;
                     }
                     break;
                 }
@@ -492,51 +538,36 @@
                 } else {
                     devices = new log_device_t(optarg, binary);
                 }
-                android::g_devCount++;
+                g_devCount++;
             }
             break;
 
             case 'B':
-                android::g_printBinary = 1;
+                g_printBinary = 1;
             break;
 
             case 'f':
                 // redirect output to a file
-
-                android::g_outputFileName = optarg;
+                g_outputFileName = optarg;
 
             break;
 
             case 'r':
-                if (optarg == NULL) {
-                    android::g_logRotateSizeKBytes
-                                = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
-                } else {
-                    if (!isdigit(optarg[0])) {
-                        fprintf(stderr,"Invalid parameter to -r\n");
-                        android::show_help(argv[0]);
-                        exit(-1);
-                    }
-                    android::g_logRotateSizeKBytes = atoi(optarg);
+                if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
+                    logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
                 }
             break;
 
             case 'n':
-                if (!isdigit(optarg[0])) {
-                    fprintf(stderr,"Invalid parameter to -r\n");
-                    android::show_help(argv[0]);
-                    exit(-1);
+                if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
+                    logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
                 }
-
-                android::g_maxRotatedLogs = atoi(optarg);
             break;
 
             case 'v':
                 err = setLogFormat (optarg);
                 if (err < 0) {
-                    fprintf(stderr,"Invalid parameter to -v\n");
-                    android::show_help(argv[0]);
-                    exit(-1);
+                    logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
                 }
 
                 if (strcmp("color", optarg)) { // exception for modifiers
@@ -582,8 +613,9 @@
                         force_exit   = 0;
                     }
                     /* if nothing found or invalid filters, exit quietly */
-                    if (force_exit)
-                        exit(0);
+                    if (force_exit) {
+                        return EXIT_SUCCESS;
+                    }
 
                     /* redirect our output to the emulator console */
                     if (console) {
@@ -615,36 +647,34 @@
                 printStatistics = 1;
                 break;
 
+            case ':':
+                logcat_panic(true, "Option -%c needs an argument\n", optopt);
+                break;
+
             default:
-                fprintf(stderr,"Unrecognized Option\n");
-                android::show_help(argv[0]);
-                exit(-1);
-            break;
+                logcat_panic(true, "Unrecognized Option %c\n", optopt);
+                break;
         }
     }
 
     if (!devices) {
         dev = devices = new log_device_t("main", false);
-        android::g_devCount = 1;
+        g_devCount = 1;
         if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
             dev = dev->next = new log_device_t("system", false);
-            android::g_devCount++;
+            g_devCount++;
         }
         if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
             dev = dev->next = new log_device_t("crash", false);
-            android::g_devCount++;
+            g_devCount++;
         }
     }
 
-    if (android::g_logRotateSizeKBytes != 0
-        && android::g_outputFileName == NULL
-    ) {
-        fprintf(stderr,"-r requires -f as well\n");
-        android::show_help(argv[0]);
-        exit(-1);
+    if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
+        logcat_panic(true, "-r requires -f as well\n");
     }
 
-    android::setupOutput();
+    setupOutput();
 
     if (hasSetLogFormat == 0) {
         const char* logFormat = getenv("ANDROID_PRINTF_LOG");
@@ -663,8 +693,7 @@
     if (forceFilters) {
         err = android_log_addFilterString(g_logformat, forceFilters);
         if (err < 0) {
-            fprintf (stderr, "Invalid filter expression in -logcat option\n");
-            exit(0);
+            logcat_panic(false, "Invalid filter expression in logcat args\n");
         }
     } else if (argc == optind) {
         // Add from environment variable
@@ -674,10 +703,8 @@
             err = android_log_addFilterString(g_logformat, env_tags_orig);
 
             if (err < 0) {
-                fprintf(stderr, "Invalid filter expression in"
-                                    " ANDROID_LOG_TAGS\n");
-                android::show_help(argv[0]);
-                exit(-1);
+                logcat_panic(true,
+                            "Invalid filter expression in ANDROID_LOG_TAGS\n");
             }
         }
     } else {
@@ -686,9 +713,7 @@
             err = android_log_addFilterString(g_logformat, argv[i]);
 
             if (err < 0) {
-                fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
-                android::show_help(argv[0]);
-                exit(-1);
+                logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
             }
         }
     }
@@ -704,22 +729,20 @@
         dev->logger = android_logger_open(logger_list,
                                           android_name_to_log_id(dev->device));
         if (!dev->logger) {
-            fprintf(stderr, "Unable to open log device '%s'\n", dev->device);
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "Unable to open log device '%s'\n",
+                         dev->device);
         }
 
         if (clearLog) {
             int ret;
             ret = android_logger_clear(dev->logger);
             if (ret) {
-                perror("failed to clear the log");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "failed to clear the log");
             }
         }
 
         if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
-            perror("failed to set the log size");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "failed to set the log size");
         }
 
         if (getLogSize) {
@@ -727,14 +750,12 @@
 
             size = android_logger_get_log_size(dev->logger);
             if (size < 0) {
-                perror("failed to get the log size");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "failed to get the log size");
             }
 
             readable = android_logger_get_log_readable_size(dev->logger);
             if (readable < 0) {
-                perror("failed to get the readable log size");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "failed to get the readable log size");
             }
 
             printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
@@ -748,16 +769,18 @@
     }
 
     if (setPruneList) {
-        size_t len = strlen(setPruneList) + 32; // margin to allow rc
-        char *buf = (char *) malloc(len);
-
-        strcpy(buf, setPruneList);
-        int ret = android_logger_set_prune_list(logger_list, buf, len);
-        free(buf);
-
-        if (ret) {
-            perror("failed to set the prune list");
-            exit(EXIT_FAILURE);
+        size_t len = strlen(setPruneList);
+        /*extra 32 bytes are needed by  android_logger_set_prune_list */
+        size_t bLen = len + 32;
+        char *buf = NULL;
+        if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
+            buf[len] = '\0';
+            if (android_logger_set_prune_list(logger_list, buf, bLen)) {
+                logcat_panic(false, "failed to set the prune list");
+            }
+            free(buf);
+        } else {
+            logcat_panic(false, "failed to set the prune list (alloc)");
         }
     }
 
@@ -767,29 +790,28 @@
 
         for(int retry = 32;
                 (retry >= 0) && ((buf = new char [len]));
-                delete [] buf, --retry) {
+                delete [] buf, buf = NULL, --retry) {
             if (getPruneList) {
                 android_logger_get_prune_list(logger_list, buf, len);
             } else {
                 android_logger_get_statistics(logger_list, buf, len);
             }
             buf[len-1] = '\0';
-            size_t ret = atol(buf) + 1;
-            if (ret < 4) {
+            if (atol(buf) < 3) {
                 delete [] buf;
                 buf = NULL;
                 break;
             }
-            bool check = ret <= len;
-            len = ret;
-            if (check) {
+            size_t ret = atol(buf) + 1;
+            if (ret <= len) {
+                len = ret;
                 break;
             }
+            len = ret;
         }
 
         if (!buf) {
-            perror("failed to read data");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "failed to read data");
         }
 
         // remove trailing FF
@@ -813,18 +835,18 @@
 
         printf("%s", cp);
         delete [] buf;
-        exit(0);
+        return EXIT_SUCCESS;
     }
 
 
     if (getLogSize) {
-        exit(0);
+        return EXIT_SUCCESS;
     }
     if (setLogSize || setPruneList) {
-        exit(0);
+        return EXIT_SUCCESS;
     }
     if (clearLog) {
-        exit(0);
+        return EXIT_SUCCESS;
     }
 
     //LOG_EVENT_INT(10, 12345);
@@ -839,8 +861,7 @@
         int ret = android_logger_list_read(logger_list, &log_msg);
 
         if (ret == 0) {
-            fprintf(stderr, "read: unexpected EOF!\n");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "read: unexpected EOF!\n");
         }
 
         if (ret < 0) {
@@ -849,15 +870,12 @@
             }
 
             if (ret == -EIO) {
-                fprintf(stderr, "read: unexpected EOF!\n");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "read: unexpected EOF!\n");
             }
             if (ret == -EINVAL) {
-                fprintf(stderr, "read: unexpected length.\n");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "read: unexpected length.\n");
             }
-            perror("logcat read failure");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "logcat read failure");
         }
 
         for(d = devices; d; d = d->next) {
@@ -866,23 +884,23 @@
             }
         }
         if (!d) {
-            android::g_devCount = 2; // set to Multiple
+            g_devCount = 2; // set to Multiple
             d = &unexpected;
             d->binary = log_msg.id() == LOG_ID_EVENTS;
         }
 
         if (dev != d) {
             dev = d;
-            android::maybePrintStart(dev, printDividers);
+            maybePrintStart(dev, printDividers);
         }
-        if (android::g_printBinary) {
-            android::printBinary(&log_msg);
+        if (g_printBinary) {
+            printBinary(&log_msg);
         } else {
-            android::processBuffer(dev, &log_msg);
+            processBuffer(dev, &log_msg);
         }
     }
 
     android_logger_list_free(logger_list);
 
-    return 0;
+    return EXIT_SUCCESS;
 }
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 015a23d..a28664e 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -39,7 +39,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SRC_FILES := $(benchmark_src_files)
 include $(BUILD_NATIVE_TEST)
@@ -56,7 +55,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/logd/Android.mk b/logd/Android.mk
index 127a66b..e65e9ff 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -32,8 +32,9 @@
 #        "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \
 #        $(LOCAL_PATH)/$2/event.logtags)
 #  event_flag := $(call event_logtags,auditd)
+#  event_flag += $(call event_logtags,logd)
 # so make sure we do not regret hard-coding it as follows:
-event_flag := -DAUDITD_LOG_TAG=1003
+event_flag := -DAUDITD_LOG_TAG=1003 -DLOGD_LOG_TAG=1004
 
 LOCAL_CFLAGS := -Werror $(event_flag)
 
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index ab00422..90370e9 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -151,9 +151,9 @@
         rc = -ENOMEM;
     } else {
         event->header.tag = htole32(AUDITD_LOG_TAG);
-        event->payload.type = EVENT_TYPE_STRING;
-        event->payload.length = htole32(l);
-        memcpy(event->payload.data, str, l);
+        event->type = EVENT_TYPE_STRING;
+        event->length = htole32(l);
+        memcpy(event->data, str, l);
 
         logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
                     reinterpret_cast<char *>(event),
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index d11b129..260e237 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -16,7 +16,6 @@
 
 #include <ctype.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include <sys/user.h>
 #include <time.h>
@@ -280,16 +279,15 @@
         size_t worst_sizes = 0;
         size_t second_worst_sizes = 0;
 
-        if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
-            const UidEntry **sorted = stats.sort(2, id);
+        if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
+            std::unique_ptr<const UidEntry *[]> sorted = stats.sort(2, id);
 
-            if (sorted) {
+            if (sorted.get()) {
                 if (sorted[0] && sorted[1]) {
                     worst = sorted[0]->getKey();
                     worst_sizes = sorted[0]->getSizes();
                     second_worst_sizes = sorted[1]->getSizes();
                 }
-                delete [] sorted;
             }
         }
 
@@ -299,6 +297,8 @@
         }
 
         bool kick = false;
+        bool leading = true;
+        LogBufferElement *last = NULL;
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
@@ -311,26 +311,87 @@
                 continue;
             }
 
-            uid_t uid = e->getUid();
+            unsigned short dropped = e->getDropped();
 
-            // !Worst and !BlackListed?
-            if ((uid != worst) && (!hasBlacklist || !mPrune.naughty(e))) {
+            // remove any leading drops
+            if (leading && dropped) {
+                it = erase(it);
+                continue;
+            }
+
+            pid_t pid = e->getPid();
+
+            // merge any drops
+            if (last && dropped
+             && ((dropped + last->getDropped()) < USHRT_MAX)
+             && (last->getPid() == pid)
+             && (last->getTid() == e->getTid())) {
+                it = mLogElements.erase(it);
+                stats.erase(e);
+                delete e;
+                last->setDropped(dropped + last->getDropped());
+                continue;
+            }
+
+            leading = false;
+
+            if (hasBlacklist && mPrune.naughty(e)) {
+                last = NULL;
+                it = erase(it);
+                if (dropped) {
+                    continue;
+                }
+
+                pruneRows--;
+                if (pruneRows == 0) {
+                    break;
+                }
+
+                if (e->getUid() == worst) {
+                    kick = true;
+                    if (worst_sizes < second_worst_sizes) {
+                        break;
+                    }
+                    worst_sizes -= e->getMsgLen();
+                }
+                continue;
+            }
+
+            if (dropped) {
+                last = e;
                 ++it;
                 continue;
             }
 
-            unsigned short len = e->getMsgLen();
-            it = erase(it);
+            if (e->getUid() != worst) {
+                last = NULL;
+                ++it;
+                continue;
+            }
+
             pruneRows--;
             if (pruneRows == 0) {
                 break;
             }
 
-            if (uid != worst) {
-                continue;
-            }
-
             kick = true;
+
+            unsigned short len = e->getMsgLen();
+            stats.drop(e);
+            e->setDropped(1);
+            // merge any drops
+            if (last
+             && (last->getDropped() < (USHRT_MAX - 1))
+             && (last->getPid() == pid)
+             && (last->getTid() == e->getTid())) {
+                it = mLogElements.erase(it);
+                stats.erase(e);
+                delete e;
+                last->setDropped(last->getDropped() + 1);
+            } else {
+                last = e;
+                ++it;
+            }
             if (worst_sizes < second_worst_sizes) {
                 break;
             }
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 5e780b5..a173e63 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,14 +14,17 @@
  * limitations under the License.
  */
 
+#include <endian.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <log/logger.h>
+#include <private/android_logger.h>
 
 #include "LogBufferElement.h"
+#include "LogCommand.h"
 #include "LogReader.h"
 
 const uint64_t LogBufferElement::FLUSH_ERROR(0);
@@ -45,11 +48,59 @@
     delete [] mMsg;
 }
 
+// assumption: mMsg == NULL
+size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) {
+    static const char format_uid[] = "uid=%u dropped=%u";
+    static const size_t unprivileged_offset = 7;
+    static const char tag[] = "logd";
+
+    size_t len;
+    if (privileged) {
+        len = snprintf(NULL, 0, format_uid, mUid, mDropped);
+    } else {
+        len = snprintf(NULL, 0, format_uid + unprivileged_offset, mDropped);
+    }
+
+    size_t hdrLen;
+    if (mLogId == LOG_ID_EVENTS) {
+        hdrLen = sizeof(android_log_event_string_t);
+    } else {
+        hdrLen = 1 + sizeof(tag);
+    }
+
+    buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
+    if (!buffer) {
+        return 0;
+    }
+
+    size_t retval = hdrLen + len;
+    if (mLogId == LOG_ID_EVENTS) {
+        android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
+
+        e->header.tag = htole32(LOGD_LOG_TAG);
+        e->type = EVENT_TYPE_STRING;
+        e->length = htole32(len);
+    } else {
+        ++retval;
+        buffer[0] = ANDROID_LOG_INFO;
+        strcpy(buffer + 1, tag);
+    }
+
+    if (privileged) {
+        snprintf(buffer + hdrLen, len + 1, format_uid, mUid, mDropped);
+    } else {
+        snprintf(buffer + hdrLen, len + 1, format_uid + unprivileged_offset, mDropped);
+    }
+
+    return retval;
+}
+
 uint64_t LogBufferElement::flushTo(SocketClient *reader) {
     struct logger_entry_v3 entry;
+
     memset(&entry, 0, sizeof(struct logger_entry_v3));
+
     entry.hdr_size = sizeof(struct logger_entry_v3);
-    entry.len = mMsgLen;
     entry.lid = mLogId;
     entry.pid = mPid;
     entry.tid = mTid;
@@ -59,11 +110,26 @@
     struct iovec iovec[2];
     iovec[0].iov_base = &entry;
     iovec[0].iov_len = sizeof(struct logger_entry_v3);
-    iovec[1].iov_base = mMsg;
-    iovec[1].iov_len = mMsgLen;
-    if (reader->sendDatav(iovec, 2)) {
-        return FLUSH_ERROR;
+
+    char *buffer = NULL;
+
+    if (!mMsg) {
+        entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader));
+        if (!entry.len) {
+            return mSequence;
+        }
+        iovec[1].iov_base = buffer;
+    } else {
+        entry.len = mMsgLen;
+        iovec[1].iov_base = mMsg;
+    }
+    iovec[1].iov_len = entry.len;
+
+    uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
+
+    if (buffer) {
+        free(buffer);
     }
 
-    return mSequence;
+    return retval;
 }
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 0628d3e..7b6456d 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -18,23 +18,42 @@
 #define _LOGD_LOG_BUFFER_ELEMENT_H__
 
 #include <stdatomic.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
 #include <sysutils/SocketClient.h>
 #include <log/log.h>
 #include <log/log_read.h>
 
+namespace android {
+
+// Furnished in main.cpp. Caller must own and free returned value
+// This function is designed for a single caller and is NOT thread-safe
+char *uidToName(uid_t uid);
+
+}
+
+static inline bool worstUidEnabledForLogid(log_id_t id) {
+    return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS);
+}
+
 class LogBufferElement {
     const log_id_t mLogId;
     const uid_t mUid;
     const pid_t mPid;
     const pid_t mTid;
     char *mMsg;
-    const unsigned short mMsgLen;
+    union {
+        const unsigned short mMsgLen; // mMSg != NULL
+        unsigned short mDropped;      // mMsg == NULL
+    };
     const uint64_t mSequence;
     const log_time mRealTime;
     static atomic_int_fast64_t sequence;
 
+    // assumption: mMsg == NULL
+    size_t populateDroppedMessage(char *&buffer, bool privileged);
+
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
                      uid_t uid, pid_t pid, pid_t tid,
@@ -45,7 +64,15 @@
     uid_t getUid(void) const { return mUid; }
     pid_t getPid(void) const { return mPid; }
     pid_t getTid(void) const { return mTid; }
-    unsigned short getMsgLen() const { return mMsgLen; }
+    unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
+    unsigned short setDropped(unsigned short value) {
+        if (mMsg) {
+            free(mMsg);
+            mMsg = NULL;
+        }
+        return mDropped = value;
+    }
+    unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; }
     uint64_t getSequence(void) const { return mSequence; }
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 6bb0b40..0801fe8 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -17,7 +17,6 @@
 #include <algorithm> // std::max
 #include <fcntl.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -27,7 +26,8 @@
 
 #include "LogStatistics.h"
 
-LogStatistics::LogStatistics() {
+LogStatistics::LogStatistics()
+        : enable(false) {
     log_id_for_each(id) {
         mSizes[id] = 0;
         mElements[id] = 0;
@@ -36,8 +36,10 @@
     }
 }
 
+namespace android {
+
 // caller must own and free character string
-char *LogStatistics::pidToName(pid_t pid) {
+static char *pidToName(pid_t pid) {
     char *retval = NULL;
     if (pid == 0) { // special case from auditd for kernel
         retval = strdup("logd.auditd");
@@ -60,6 +62,8 @@
     return retval;
 }
 
+}
+
 void LogStatistics::add(LogBufferElement *e) {
     log_id_t log_id = e->getLogId();
     unsigned short size = e->getMsgLen();
@@ -67,20 +71,50 @@
     ++mElements[log_id];
 
     uid_t uid = e->getUid();
+    unsigned short dropped = e->getDropped();
     android::hash_t hash = android::hash_type(uid);
     uidTable_t &table = uidTable[log_id];
     ssize_t index = table.find(-1, hash, uid);
     if (index == -1) {
         UidEntry initEntry(uid);
         initEntry.add(size);
+        initEntry.add_dropped(dropped);
         table.add(hash, initEntry);
     } else {
         UidEntry &entry = table.editEntryAt(index);
         entry.add(size);
+        entry.add_dropped(dropped);
     }
 
     mSizesTotal[log_id] += size;
     ++mElementsTotal[log_id];
+
+    if (!enable) {
+        return;
+    }
+
+    pid_t pid = e->getPid();
+    hash = android::hash_type(pid);
+    index = pidTable.find(-1, hash, pid);
+    if (index == -1) {
+        PidEntry initEntry(pid, uid, android::pidToName(pid));
+        initEntry.add(size);
+        initEntry.add_dropped(dropped);
+        pidTable.add(hash, initEntry);
+    } else {
+        PidEntry &entry = pidTable.editEntryAt(index);
+        if (entry.getUid() != uid) {
+            entry.setUid(uid);
+            entry.setName(android::pidToName(pid));
+        } else if (!entry.getName()) {
+            char *name = android::pidToName(pid);
+            if (name) {
+                entry.setName(name);
+            }
+        }
+        entry.add(size);
+        entry.add_dropped(dropped);
+    }
 }
 
 void LogStatistics::subtract(LogBufferElement *e) {
@@ -90,42 +124,61 @@
     --mElements[log_id];
 
     uid_t uid = e->getUid();
+    unsigned short dropped = e->getDropped();
     android::hash_t hash = android::hash_type(uid);
     uidTable_t &table = uidTable[log_id];
     ssize_t index = table.find(-1, hash, uid);
     if (index != -1) {
         UidEntry &entry = table.editEntryAt(index);
-        if (entry.subtract(size)) {
+        if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
             table.removeAt(index);
         }
     }
+
+    if (!enable) {
+        return;
+    }
+
+    pid_t pid = e->getPid();
+    hash = android::hash_type(pid);
+    index = pidTable.find(-1, hash, pid);
+    if (index != -1) {
+        PidEntry &entry = pidTable.editEntryAt(index);
+        if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
+            pidTable.removeAt(index);
+        }
+    }
 }
 
-// caller must own and delete UidEntry array
-const UidEntry **LogStatistics::sort(size_t n, log_id id) {
-    if (!n) {
-        return NULL;
+// Atomically set an entry to drop
+// entry->setDropped(1) must follow this call, caller should do this explicitly.
+void LogStatistics::drop(LogBufferElement *e) {
+    log_id_t log_id = e->getLogId();
+    unsigned short size = e->getMsgLen();
+    mSizes[log_id] -= size;
+
+    uid_t uid = e->getUid();
+    android::hash_t hash = android::hash_type(uid);
+    typeof uidTable[0] &table = uidTable[log_id];
+    ssize_t index = table.find(-1, hash, uid);
+    if (index != -1) {
+        UidEntry &entry = table.editEntryAt(index);
+        entry.subtract(size);
+        entry.add_dropped(1);
     }
 
-    const UidEntry **retval = new const UidEntry* [n];
-    memset(retval, 0, sizeof(*retval) * n);
-
-    uidTable_t &table = uidTable[id];
-    ssize_t index = -1;
-    while ((index = table.next(index)) >= 0) {
-        const UidEntry &entry = table.entryAt(index);
-        size_t s = entry.getSizes();
-        ssize_t i = n - 1;
-        while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0));
-        if (++i < (ssize_t)n) {
-            size_t b = n - i - 1;
-            if (b) {
-                memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
-            }
-            retval[i] = &entry;
-        }
+    if (!enable) {
+        return;
     }
-    return retval;
+
+    pid_t pid = e->getPid();
+    hash = android::hash_type(pid);
+    index = pidTable.find(-1, hash, pid);
+    if (index != -1) {
+        PidEntry &entry = pidTable.editEntryAt(index);
+        entry.subtract(size);
+        entry.add_dropped(1);
+    }
 }
 
 // caller must own and free character string
@@ -145,17 +198,52 @@
         ++info;
     }
 
+    // Parse /data/system/packages.list
+    char *name = android::uidToName(uid);
+    if (name) {
+        return name;
+    }
+
+    // report uid -> pid(s) -> pidToName if unique
+    ssize_t index = -1;
+    while ((index = pidTable.next(index)) != -1) {
+        const PidEntry &entry = pidTable.entryAt(index);
+
+        if (entry.getUid() == uid) {
+            const char *n = entry.getName();
+
+            if (n) {
+                if (!name) {
+                    name = strdup(n);
+                } else if (strcmp(name, n)) {
+                    free(name);
+                    return NULL;
+                }
+            }
+        }
+    }
+
     // No one
-    return NULL;
+    return name;
 }
 
 static void format_line(android::String8 &output,
-        android::String8 &name, android::String8 &size) {
-    static const size_t total_len = 70;
+        android::String8 &name, android::String8 &size, android::String8 &pruned) {
+    static const size_t pruned_len = 6;
+    static const size_t total_len = 70 + pruned_len;
 
-    output.appendFormat("%s%*s\n", name.string(),
-        (int)std::max(total_len - name.length() - 1, size.length() + 1),
-        size.string());
+    ssize_t drop_len = std::max(pruned.length() + 1, pruned_len);
+    ssize_t size_len = std::max(size.length() + 1,
+                                total_len - name.length() - drop_len - 1);
+
+    if (pruned.length()) {
+        output.appendFormat("%s%*s%*s\n", name.string(),
+                                          (int)size_len, size.string(),
+                                          (int)drop_len, pruned.string());
+    } else {
+        output.appendFormat("%s%*s\n", name.string(),
+                                       (int)size_len, size.string());
+    }
 }
 
 void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
@@ -223,50 +311,40 @@
     // Report on Chattiest
 
     // Chattiest by application (UID)
+    static const size_t maximum_sorted_entries = 32;
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
             continue;
         }
 
-        static const size_t maximum_sorted_entries = 32;
-        const UidEntry **sorted = sort(maximum_sorted_entries, id);
-
-        if (!sorted) {
-            continue;
-        }
-
-        bool print = false;
-        for(size_t index = 0; index < maximum_sorted_entries; ++index) {
+        bool headerPrinted = false;
+        std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
+        ssize_t index = -1;
+        while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
             const UidEntry *entry = sorted[index];
-
-            if (!entry) {
-                break;
-            }
-
-            size_t sizes = entry->getSizes();
-            if (sizes < (65536/100)) {
-                break;
-            }
-
             uid_t u = entry->getKey();
             if ((uid != AID_ROOT) && (u != uid)) {
                 continue;
             }
 
-            if (!print) {
+            if (!headerPrinted) {
                 if (uid == AID_ROOT) {
                     output.appendFormat(
                         "\n\nChattiest UIDs in %s:\n",
                         android_log_id_to_name(id));
-                    android::String8 name("UID");
-                    android::String8 size("Size");
-                    format_line(output, name, size);
                 } else {
                     output.appendFormat(
                         "\n\nLogging for your UID in %s:\n",
                         android_log_id_to_name(id));
                 }
-                print = true;
+                android::String8 name("UID");
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                if (!worstUidEnabledForLogid(id)) {
+                    pruned.setTo("");
+                }
+                format_line(output, name, size, pruned);
+                headerPrinted = true;
             }
 
             android::String8 name("");
@@ -278,25 +356,81 @@
             }
 
             android::String8 size("");
-            size.appendFormat("%zu", sizes);
+            size.appendFormat("%zu", entry->getSizes());
 
-            format_line(output, name, size);
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
+            }
+
+            format_line(output, name, size, pruned);
         }
+    }
 
-        delete [] sorted;
+    if (enable) {
+        bool headerPrinted = false;
+        std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const PidEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            if (!headerPrinted) {
+                if (uid == AID_ROOT) {
+                    output.appendFormat("\n\nChattiest PIDs:\n");
+                } else {
+                    output.appendFormat("\n\nLogging for this PID:\n");
+                }
+                android::String8 name("  PID/UID");
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                format_line(output, name, size, pruned);
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            name.appendFormat("%5u/%u", entry->getKey(), u);
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+            } else {
+                char *un = uidToName(u);
+                if (un) {
+                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    free(un);
+                }
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
+            }
+
+            format_line(output, name, size, pruned);
+        }
     }
 
     *buf = strdup(output.string());
 }
 
-uid_t LogStatistics::pidToUid(pid_t pid) {
+namespace android {
+
+uid_t pidToUid(pid_t pid) {
     char buffer[512];
     snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
     FILE *fp = fopen(buffer, "r");
     if (fp) {
         while (fgets(buffer, sizeof(buffer), fp)) {
             int uid;
-            if (sscanf(buffer, "Groups: %d", &uid) == 1) {
+            if (sscanf(buffer, "Uid: %d", &uid) == 1) {
                 fclose(fp);
                 return uid;
             }
@@ -305,3 +439,52 @@
     }
     return AID_LOGD; // associate this with the logger
 }
+
+}
+
+uid_t LogStatistics::pidToUid(pid_t pid) {
+    uid_t uid;
+    android::hash_t hash = android::hash_type(pid);
+    ssize_t index = pidTable.find(-1, hash, pid);
+    if (index == -1) {
+        uid = android::pidToUid(pid);
+        PidEntry initEntry(pid, uid, android::pidToName(pid));
+        pidTable.add(hash, initEntry);
+    } else {
+        PidEntry &entry = pidTable.editEntryAt(index);
+        if (!entry.getName()) {
+            char *name = android::pidToName(pid);
+            if (name) {
+                entry.setName(name);
+            }
+        }
+        uid = entry.getUid();
+    }
+    return uid;
+}
+
+// caller must free character string
+char *LogStatistics::pidToName(pid_t pid) {
+    char *name;
+
+    android::hash_t hash = android::hash_type(pid);
+    ssize_t index = pidTable.find(-1, hash, pid);
+    if (index == -1) {
+        name = android::pidToName(pid);
+        PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL);
+        pidTable.add(hash, initEntry);
+    } else {
+        PidEntry &entry = pidTable.editEntryAt(index);
+        const char *n = entry.getName();
+        if (n) {
+            name = strdup(n);
+        } else {
+            name = android::pidToName(pid);
+            if (name) {
+                entry.setName(strdup(name));
+            }
+        }
+    }
+
+    return name;
+}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index d5b8762..f3110d7 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -17,6 +17,8 @@
 #ifndef _LOGD_LOG_STATISTICS_H__
 #define _LOGD_LOG_STATISTICS_H__
 
+#include <memory>
+#include <stdlib.h>
 #include <sys/types.h>
 
 #include <log/log.h>
@@ -27,16 +29,96 @@
 #define log_id_for_each(i) \
     for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
 
+template <typename TKey, typename TEntry>
+class LogHashtable : public android::BasicHashtable<TKey, TEntry> {
+public:
+    std::unique_ptr<const TEntry *[]> sort(size_t n) {
+        if (!n) {
+            std::unique_ptr<const TEntry *[]> sorted(NULL);
+            return sorted;
+        }
+
+        const TEntry **retval = new const TEntry* [n];
+        memset(retval, 0, sizeof(*retval) * n);
+
+        ssize_t index = -1;
+        while ((index = android::BasicHashtable<TKey, TEntry>::next(index)) >= 0) {
+            const TEntry &entry = android::BasicHashtable<TKey, TEntry>::entryAt(index);
+            size_t s = entry.getSizes();
+            ssize_t i = n - 1;
+            while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0))
+                ;
+            if (++i < (ssize_t)n) {
+                size_t b = n - i - 1;
+                if (b) {
+                    memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
+                }
+                retval[i] = &entry;
+            }
+        }
+        std::unique_ptr<const TEntry *[]> sorted(retval);
+        return sorted;
+    }
+
+    // Iteration handler for the sort method output
+    static ssize_t next(ssize_t index, std::unique_ptr<const TEntry *[]> &sorted, size_t n) {
+        ++index;
+        if (!sorted.get() || (index < 0) || (n <= (size_t)index) || !sorted[index]
+         || (sorted[index]->getSizes() <= (sorted[0]->getSizes() / 100))) {
+            return -1;
+        }
+        return index;
+    }
+
+    ssize_t next(ssize_t index) {
+        return android::BasicHashtable<TKey, TEntry>::next(index);
+    }
+};
+
 struct UidEntry {
     const uid_t uid;
     size_t size;
+    size_t dropped;
 
-    UidEntry(uid_t uid):uid(uid),size(0) { }
+    UidEntry(uid_t uid):uid(uid),size(0),dropped(0) { }
 
     inline const uid_t&getKey() const { return uid; }
     size_t getSizes() const { return size; }
+    size_t getDropped() const { return dropped; }
+
     inline void add(size_t s) { size += s; }
-    inline bool subtract(size_t s) { size -= s; return !size; }
+    inline void add_dropped(size_t d) { dropped += d; }
+    inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
+    inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+};
+
+struct PidEntry {
+    const pid_t pid;
+    uid_t uid;
+    char *name;
+    size_t size;
+    size_t dropped;
+
+    PidEntry(pid_t p, uid_t u, char *n):pid(p),uid(u),name(n),size(0),dropped(0) { }
+    PidEntry(const PidEntry &c):
+        pid(c.pid),
+        uid(c.uid),
+        name(c.name ? strdup(c.name) : NULL),
+        size(c.size),
+        dropped(c.dropped) { }
+    ~PidEntry() { free(name); }
+
+    const pid_t&getKey() const { return pid; }
+    const uid_t&getUid() const { return uid; }
+    uid_t&setUid(uid_t u) { return uid = u; }
+    const char*getName() const { return name; }
+    char *setName(char *n) { free(name); return name = n; }
+    size_t getSizes() const { return size; }
+    size_t getDropped() const { return dropped; }
+    inline void add(size_t s) { size += s; }
+    inline void add_dropped(size_t d) { dropped += d; }
+    inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
+    inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
 };
 
 // Log Statistics
@@ -45,21 +127,29 @@
     size_t mElements[LOG_ID_MAX];
     size_t mSizesTotal[LOG_ID_MAX];
     size_t mElementsTotal[LOG_ID_MAX];
+    bool enable;
 
     // uid to size list
-    typedef android::BasicHashtable<uid_t, UidEntry> uidTable_t;
+    typedef LogHashtable<uid_t, UidEntry> uidTable_t;
     uidTable_t uidTable[LOG_ID_MAX];
 
+    // pid to uid list
+    typedef LogHashtable<pid_t, PidEntry> pidTable_t;
+    pidTable_t pidTable;
+
 public:
     LogStatistics();
 
-    void enableStatistics() { }
+    void enableStatistics() { enable = true; }
 
     void add(LogBufferElement *entry);
     void subtract(LogBufferElement *entry);
+    // entry->setDropped(1) must follow this call
+    void drop(LogBufferElement *entry);
+    // Correct for merging two entries referencing dropped content
+    void erase(LogBufferElement *e) { --mElements[e->getLogId()]; }
 
-    // Caller must delete array
-    const UidEntry **sort(size_t n, log_id i);
+    std::unique_ptr<const UidEntry *[]> sort(size_t n, log_id i) { return uidTable[i].sort(n); }
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 6910854..bee940d 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -15,7 +15,6 @@
  */
 
 #include <ctype.h>
-#include <malloc.h>
 
 #include <utils/String8.h>
 
@@ -53,7 +52,7 @@
 }
 
 PruneList::PruneList()
-        : mWorstUidEnabled(false) {
+        : mWorstUidEnabled(true) {
     mNaughty.clear();
     mNice.clear();
 }
@@ -71,7 +70,7 @@
 }
 
 int PruneList::init(char *str) {
-    mWorstUidEnabled = false;
+    mWorstUidEnabled = true;
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
         delete (*it);
diff --git a/logd/event.logtags b/logd/event.logtags
index a63f034..db8c19b 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -34,3 +34,4 @@
 # TODO: generate ".java" and ".h" files with integer constants from this file.
 
 1003  auditd (avc|3)
+1004  logd (dropped|3)
diff --git a/logd/main.cpp b/logd/main.cpp
index 3ddc1df..4aa38b3 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -143,6 +143,10 @@
 //   write(fdDmesg, "I am here\n", 10);
 static int fdDmesg = -1;
 
+static sem_t uidName;
+static uid_t uid;
+static char *name;
+
 static sem_t reinit;
 static bool reinit_running = false;
 static LogBuffer *logBuf = NULL;
@@ -151,10 +155,45 @@
     prctl(PR_SET_NAME, "logd.daemon");
     set_sched_policy(0, SP_BACKGROUND);
 
-    setgid(AID_LOGD);
-    setuid(AID_LOGD);
+    setgid(AID_SYSTEM);
+    setuid(AID_SYSTEM);
 
     while (reinit_running && !sem_wait(&reinit) && reinit_running) {
+
+        // uidToName Privileged Worker
+        if (uid) {
+            name = NULL;
+
+            FILE *fp = fopen("/data/system/packages.list", "r");
+            if (fp) {
+                // This simple parser is sensitive to format changes in
+                // frameworks/base/services/core/java/com/android/server/pm/Settings.java
+                // A dependency note has been added to that file to correct
+                // this parser.
+
+                char *buffer = NULL;
+                size_t len;
+                while (getline(&buffer, &len, fp) > 0) {
+                    char *userId = strchr(buffer, ' ');
+                    if (!userId) {
+                        continue;
+                    }
+                    *userId = '\0';
+                    unsigned long value = strtoul(userId + 1, NULL, 10);
+                    if (value != uid) {
+                        continue;
+                    }
+                    name = strdup(buffer);
+                    break;
+                }
+                free(buffer);
+                fclose(fp);
+            }
+            uid = 0;
+            sem_post(&uidName);
+            continue;
+        }
+
         if (fdDmesg >= 0) {
             static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO),
                 'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':',
@@ -171,6 +210,20 @@
     return NULL;
 }
 
+char *android::uidToName(uid_t u) {
+    if (!u || !reinit_running) {
+        return NULL;
+    }
+
+    // Not multi-thread safe, we know there is only one caller
+    uid = u;
+
+    name = NULL;
+    sem_post(&reinit);
+    sem_wait(&uidName);
+    return name;
+}
+
 // Serves as a global method to trigger reinitialization
 // and as a function that can be provided to signal().
 void reinit_signal_handler(int /*signal*/) {
@@ -223,6 +276,7 @@
 
     // Reinit Thread
     sem_init(&reinit, 0, 0);
+    sem_init(&uidName, 0, 0);
     pthread_attr_t attr;
     if (!pthread_attr_init(&attr)) {
         struct sched_param param;
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index f851288..85ca4ac 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -46,7 +46,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := libcutils
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index cda79ce..a2b8f59 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -188,6 +188,7 @@
 
 
 on post-fs
+    start logd
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
     # mount shared so changes propagate into child namespaces
@@ -311,6 +312,7 @@
     mkdir /data/media 0770 media_rw media_rw
     mkdir /data/ss 0700 system system
     mkdir /data/system 0775 system system
+    mkdir /data/system/heapdump 0700 system system
     mkdir /data/user 0711 system system
 
     # Reload policy from /data/security if present.
@@ -319,6 +321,9 @@
     # Set SELinux security contexts on upgrade or policy update.
     restorecon_recursive /data
 
+    # Check any timezone data in /data is newer than the copy in /system, delete if not.
+    exec u:r:tzdatacheck:s0 system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
+
     # If there is no fs-post-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -484,6 +489,7 @@
     socket logdw dgram 0222 logd logd
 
 service logd-reinit /system/bin/logd --reinit
+    start logd
     oneshot
     disabled
 
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 4d50bf0..041c37a 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -199,6 +199,8 @@
      * position. Used to support things like OBB. */
     char* graft_path;
     size_t graft_pathlen;
+
+    bool deleted;
 };
 
 static int str_hash(void *key) {
@@ -631,6 +633,8 @@
     node->ino = fuse->inode_ctr++;
     node->gen = fuse->next_generation++;
 
+    node->deleted = false;
+
     derive_permissions_locked(fuse, parent, node);
     acquire_node_locked(node);
     add_node_to_parent_locked(node, parent);
@@ -704,7 +708,7 @@
          * must be considered distinct even if they refer to the same
          * underlying file as otherwise operations such as "mv x x"
          * will not work because the source and target nodes are the same. */
-        if (!strcmp(name, node->name)) {
+        if (!strcmp(name, node->name) && !node->deleted) {
             return node;
         }
     }
@@ -1070,6 +1074,7 @@
 {
     bool has_rw;
     struct node* parent_node;
+    struct node* child_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
@@ -1091,6 +1096,12 @@
     if (unlink(child_path) < 0) {
         return -errno;
     }
+    pthread_mutex_lock(&fuse->lock);
+    child_node = lookup_child_by_name_locked(parent_node, name);
+    if (child_node) {
+        child_node->deleted = true;
+    }
+    pthread_mutex_unlock(&fuse->lock);
     return 0;
 }
 
@@ -1098,6 +1109,7 @@
         const struct fuse_in_header* hdr, const char* name)
 {
     bool has_rw;
+    struct node* child_node;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
@@ -1120,6 +1132,12 @@
     if (rmdir(child_path) < 0) {
         return -errno;
     }
+    pthread_mutex_lock(&fuse->lock);
+    child_node = lookup_child_by_name_locked(parent_node, name);
+    if (child_node) {
+        child_node->deleted = true;
+    }
+    pthread_mutex_unlock(&fuse->lock);
     return 0;
 }
 
@@ -1869,7 +1887,8 @@
             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
             fd, uid, gid);
 
-    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts);
+    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
+            MS_NOATIME, opts);
     if (res < 0) {
         ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
         goto error;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 4e54eb8..ad99a39 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -23,14 +23,12 @@
     upstream-netbsd/lib/libutil/raise_default_signal.c
 LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV
 LOCAL_MODULE := libtoolbox_dd
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := upstream-netbsd/usr.bin/du/du.c
 LOCAL_CFLAGS += $(common_cflags) -Dmain=du_main
 LOCAL_MODULE := libtoolbox_du
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -43,7 +41,6 @@
 OUR_TOOLS := \
     df \
     getevent \
-    getprop \
     iftop \
     ioctl \
     ionice \
@@ -56,20 +53,16 @@
     ps \
     prlimit \
     renice \
-    restorecon \
     sendevent \
-    setprop \
     start \
     stop \
     top \
-    umount \
     uptime \
     watchprops \
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
 LOCAL_SRC_FILES := \
-    dynarray.c \
     toolbox.c \
     $(patsubst %,%.c,$(OUR_TOOLS)) \
 
@@ -82,7 +75,6 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
 
 LOCAL_MODULE := toolbox
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 # Install the symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toolbox $(TARGET_OUT)/bin/$(t);)
@@ -115,7 +107,6 @@
 LOCAL_CFLAGS += $(common_cflags)
 LOCAL_MODULE := r
 LOCAL_MODULE_TAGS := debug
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
 
diff --git a/toolbox/dynarray.c b/toolbox/dynarray.c
deleted file mode 100644
index 47594e0..0000000
--- a/toolbox/dynarray.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "dynarray.h"
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-void
-dynarray_init( dynarray_t *a )
-{
-    a->count = a->capacity = 0;
-    a->items = NULL;
-}
-
-
-static void
-dynarray_reserve_more( dynarray_t *a, int count )
-{
-    int old_cap = a->capacity;
-    int new_cap = old_cap;
-    const int max_cap = INT_MAX/sizeof(void*);
-    void** new_items;
-    int new_count = a->count + count;
-
-    if (count <= 0)
-        return;
-
-    if (count > max_cap - a->count)
-        abort();
-
-    new_count = a->count + count;
-
-    while (new_cap < new_count) {
-        old_cap = new_cap;
-        new_cap += (new_cap >> 2) + 4;
-        if (new_cap < old_cap || new_cap > max_cap) {
-            new_cap = max_cap;
-        }
-    }
-    new_items = realloc(a->items, new_cap*sizeof(void*));
-    if (new_items == NULL)
-        abort();
-
-    a->items = new_items;
-    a->capacity = new_cap;
-}
-
-void
-dynarray_append( dynarray_t *a, void* item )
-{
-    if (a->count >= a->capacity)
-        dynarray_reserve_more(a, 1);
-
-    a->items[a->count++] = item;
-}
-
-void
-dynarray_done( dynarray_t *a )
-{
-    free(a->items);
-    a->items = NULL;
-    a->count = a->capacity = 0;
-}
-
-// string arrays
-
-void strlist_init( strlist_t *list )
-{
-    dynarray_init(list);
-}
-
-void strlist_append_b( strlist_t *list, const void* str, size_t  slen )
-{
-    char *copy = malloc(slen+1);
-    memcpy(copy, str, slen);
-    copy[slen] = '\0';
-    dynarray_append(list, copy);
-}
-
-void strlist_append_dup( strlist_t *list, const char *str)
-{
-    strlist_append_b(list, str, strlen(str));
-}
-
-void strlist_done( strlist_t *list )
-{
-    STRLIST_FOREACH(list, string, free(string));
-    dynarray_done(list);
-}
-
-static int strlist_compare_strings(const void* a, const void* b)
-{
-    const char *sa = *(const char **)a;
-    const char *sb = *(const char **)b;
-    return strcmp(sa, sb);
-}
-
-void strlist_sort( strlist_t *list )
-{
-    if (list->count > 0) {
-        qsort(list->items,
-              (size_t)list->count,
-              sizeof(void*),
-              strlist_compare_strings);
-    }
-}
diff --git a/toolbox/dynarray.h b/toolbox/dynarray.h
deleted file mode 100644
index f73fb3b..0000000
--- a/toolbox/dynarray.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef DYNARRAY_H
-#define DYNARRAY_H
-
-#include <stddef.h>
-
-/* simple dynamic array of pointers */
-typedef struct {
-    int count;
-    int capacity;
-    void** items;
-} dynarray_t;
-
-#define DYNARRAY_INITIALIZER  { 0, 0, NULL }
-
-void dynarray_init( dynarray_t *a );
-void dynarray_done( dynarray_t *a );
-
-void dynarray_append( dynarray_t *a, void* item );
-
-/* Used to iterate over a dynarray_t
- * _array :: pointer to the array
- * _item_type :: type of objects pointed to by the array
- * _item      :: name of a local variable defined within the loop
- *               with type '_item_type'
- * _stmnt     :: C statement that will be executed in each iteration.
- *
- * You case use 'break' and 'continue' within _stmnt
- *
- * This macro is only intended for simple uses. I.e. do not add or
- * remove items from the array during iteration.
- */
-#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
-    do { \
-        int _nn_##__LINE__ = 0; \
-        for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
-            _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
-            _stmnt; \
-        } \
-    } while (0)
-
-#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
-    DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
-
-/* Simple dynamic string arrays
- *
- * NOTE: A strlist_t owns the strings it references.
- */
-typedef dynarray_t  strlist_t;
-
-#define  STRLIST_INITIALIZER  DYNARRAY_INITIALIZER
-
-/* Used to iterate over a strlist_t
- * _list   :: pointer to strlist_t object
- * _string :: name of local variable name defined within the loop with
- *            type 'char*'
- * _stmnt  :: C statement executed in each iteration
- *
- * This macro is only intended for simple uses. Do not add or remove items
- * to/from the list during iteration.
- */
-#define  STRLIST_FOREACH(_list,_string,_stmnt) \
-    DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
-
-void strlist_init( strlist_t *list );
-
-/* note: strlist_done will free all the strings owned by the list */
-void strlist_done( strlist_t *list );
-
-/* append a new string made of the first 'slen' characters from 'str'
- * followed by a trailing zero.
- */
-void strlist_append_b( strlist_t *list, const void* str, size_t  slen );
-
-/* append the copy of a given input string to a strlist_t */
-void strlist_append_dup( strlist_t *list, const char *str);
-
-/* sort the strings in a given list (using strcmp) */
-void strlist_sort( strlist_t *list );
-
-#endif /* DYNARRAY_H */
\ No newline at end of file
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
deleted file mode 100644
index dcc0ea0..0000000
--- a/toolbox/getprop.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-
-#include "dynarray.h"
-
-static void record_prop(const char* key, const char* name, void* opaque)
-{
-    strlist_t* list = opaque;
-    char temp[PROP_VALUE_MAX + PROP_NAME_MAX + 16];
-    snprintf(temp, sizeof temp, "[%s]: [%s]", key, name);
-    strlist_append_dup(list, temp);
-}
-
-static void list_properties(void)
-{
-    strlist_t  list[1] = { STRLIST_INITIALIZER };
-
-    /* Record properties in the string list */
-    (void)property_list(record_prop, list);
-
-    /* Sort everything */
-    strlist_sort(list);
-
-    /* print everything */
-    STRLIST_FOREACH(list, str, printf("%s\n", str));
-
-    /* voila */
-    strlist_done(list);
-}
-
-int getprop_main(int argc, char *argv[])
-{
-    if (argc == 1) {
-        list_properties();
-    } else {
-        char value[PROPERTY_VALUE_MAX];
-        char *default_value;
-        if(argc > 2) {
-            default_value = argv[2];
-        } else {
-            default_value = "";
-        }
-
-        property_get(argv[1], value, default_value);
-        printf("%s\n", value);
-    }
-    return 0;
-}
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index d1cc14a..093e467 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -1,36 +1,81 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <error.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <errno.h>
-#include <pthread.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 
-int ioctl_main(int argc, char *argv[])
-{
-    int c;
-    int fd;
-    int res;
+static void usage() {
+    fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
+            "  -l <length>   Length of io buffer\n"
+            "  -a <argsize>  Size of each argument (1-8)\n"
+            "  -r            Open device in read only mode\n"
+            "  -d            Direct argument (no iobuffer)\n"
+            "  -h            Print help\n", getprogname());
+    exit(1);
+}
 
+static int xstrtoi(const char* s, const char* what) {
+    char* endp;
+    errno = 0;
+    long result = strtol(s, &endp, 0);
+    if (errno != 0 || *endp != '\0') {
+        error(1, errno, "couldn't parse %s '%s'", what, s);
+    }
+    if (result > INT_MAX || result < INT_MIN) {
+        error(1, errno, "%s '%s' out of range", what, s);
+    }
+    return result;
+}
+
+int ioctl_main(int argc, char* argv[]) {
     int read_only = 0;
     int length = -1;
     int arg_size = 4;
     int direct_arg = 0;
-    uint32_t ioctl_nr;
+
     void *ioctl_args = NULL;
     uint8_t *ioctl_argp;
     uint8_t *ioctl_argp_save = NULL;
     int rem;
 
-    do {
-        c = getopt(argc, argv, "rdl:a:h");
-        if (c == EOF)
-            break;
+    int c;
+    while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
         switch (c) {
         case 'r':
             read_only = 1;
@@ -39,43 +84,44 @@
             direct_arg = 1;
             break;
         case 'l':
-            length = strtol(optarg, NULL, 0);
+            length = xstrtoi(optarg, "length");
             break;
         case 'a':
-            arg_size = strtol(optarg, NULL, 0);
+            arg_size = xstrtoi(optarg, "argument size");
             break;
         case 'h':
-            fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
-                    "  -l <length>   Length of io buffer\n"
-                    "  -a <argsize>  Size of each argument (1-8)\n"
-                    "  -r            Open device in read only mode\n"
-                    "  -d            Direct argument (no iobuffer)\n"
-                    "  -h            Print help\n", argv[0]);
-            return -1;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
+            usage();
+            break;
+        default:
+            error(1, 0, "invalid option -%c", optopt);
         }
-    } while (1);
-
-    if(optind + 2 > argc) {
-        fprintf(stderr, "%s: too few arguments\n", argv[0]);
-        exit(1);
     }
 
-    if (!strcmp(argv[optind], "-")) {
+    if (optind + 2 > argc) {
+        usage();
+    }
+
+    const char* device = argv[optind];
+    int fd;
+    if (strcmp(device, "-") == 0) {
         fd = STDIN_FILENO;
     } else {
-        fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC));
-        if (fd < 0) {
-            fprintf(stderr, "cannot open %s\n", argv[optind]);
-            return 1;
+        fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
+        if (fd == -1) {
+            error(1, errno, "cannot open %s", argv[optind]);
         }
     }
     optind++;
-    
-    ioctl_nr = strtol(argv[optind], NULL, 0);
+
+    // IOCTL(2) wants second parameter as a signed int.
+    // Let's let the user specify either negative numbers or large positive
+    // numbers, for the case where ioctl number is larger than INT_MAX.
+    errno = 0;
+    char* endp;
+    int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
+    if (errno != 0 || *endp != '\0') {
+        error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
+    }
     optind++;
 
     if(direct_arg) {
@@ -91,11 +137,10 @@
 
         ioctl_argp_save = ioctl_argp = ioctl_args;
         rem = length;
-        while(optind < argc) {
+        while (optind < argc) {
             uint64_t tmp = strtoull(argv[optind], NULL, 0);
-            if(rem < arg_size) {
-                fprintf(stderr, "%s: too many arguments\n", argv[0]);
-                exit(1);
+            if (rem < arg_size) {
+                error(1, 0, "too many arguments");
             }
             memcpy(ioctl_argp, &tmp, arg_size);
             ioctl_argp += arg_size;
@@ -108,8 +153,9 @@
     while(rem--) {
         printf(" 0x%02x", *ioctl_argp_save++);
     }
-    printf("\n");
+    printf(" to %s\n", device);
 
+    int res;
     if(direct_arg)
         res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
     else if(length)
@@ -118,10 +164,10 @@
         res = ioctl(fd, ioctl_nr, 0);
     if (res < 0) {
         free(ioctl_args);
-        fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
-        return 1;
+        error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
     }
-    if(length) {
+
+    if (length) {
         printf("return buf:");
         ioctl_argp = ioctl_args;
         rem = length;
@@ -131,5 +177,6 @@
         printf("\n");
     }
     free(ioctl_args);
+    close(fd);
     return 0;
 }
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 963fcb5..9a89dd4 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -1,23 +1,119 @@
+#include <dirent.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <selinux/selinux.h>
 
-#include <sys/stat.h>
-#include <unistd.h>
-#include <time.h>
+// simple dynamic array of strings.
+typedef struct {
+    int count;
+    int capacity;
+    void** items;
+} strlist_t;
 
-#include <pwd.h>
-#include <grp.h>
+#define STRLIST_INITIALIZER { 0, 0, NULL }
 
-#include <linux/kdev_t.h>
-#include <limits.h>
+/* Used to iterate over a strlist_t
+ * _list   :: pointer to strlist_t object
+ * _item   :: name of local variable name defined within the loop with
+ *            type 'char*'
+ * _stmnt  :: C statement executed in each iteration
+ *
+ * This macro is only intended for simple uses. Do not add or remove items
+ * to/from the list during iteration.
+ */
+#define  STRLIST_FOREACH(_list,_item,_stmnt) \
+    do { \
+        int _nn_##__LINE__ = 0; \
+        for (;_nn_##__LINE__ < (_list)->count; ++ _nn_##__LINE__) { \
+            char* _item = (char*)(_list)->items[_nn_##__LINE__]; \
+            _stmnt; \
+        } \
+    } while (0)
 
-#include "dynarray.h"
+static void dynarray_reserve_more( strlist_t *a, int count ) {
+    int old_cap = a->capacity;
+    int new_cap = old_cap;
+    const int max_cap = INT_MAX/sizeof(void*);
+    void** new_items;
+    int new_count = a->count + count;
+
+    if (count <= 0)
+        return;
+
+    if (count > max_cap - a->count)
+        abort();
+
+    new_count = a->count + count;
+
+    while (new_cap < new_count) {
+        old_cap = new_cap;
+        new_cap += (new_cap >> 2) + 4;
+        if (new_cap < old_cap || new_cap > max_cap) {
+            new_cap = max_cap;
+        }
+    }
+    new_items = realloc(a->items, new_cap*sizeof(void*));
+    if (new_items == NULL)
+        abort();
+
+    a->items = new_items;
+    a->capacity = new_cap;
+}
+
+void strlist_init( strlist_t *list ) {
+    list->count = list->capacity = 0;
+    list->items = NULL;
+}
+
+// append a new string made of the first 'slen' characters from 'str'
+// followed by a trailing zero.
+void strlist_append_b( strlist_t *list, const void* str, size_t  slen ) {
+    char *copy = malloc(slen+1);
+    memcpy(copy, str, slen);
+    copy[slen] = '\0';
+    if (list->count >= list->capacity)
+        dynarray_reserve_more(list, 1);
+    list->items[list->count++] = copy;
+}
+
+// append the copy of a given input string to a strlist_t.
+void strlist_append_dup( strlist_t *list, const char *str) {
+    strlist_append_b(list, str, strlen(str));
+}
+
+// note: strlist_done will free all the strings owned by the list.
+void strlist_done( strlist_t *list ) {
+    STRLIST_FOREACH(list, string, free(string));
+    free(list->items);
+    list->items = NULL;
+    list->count = list->capacity = 0;
+}
+
+static int strlist_compare_strings(const void* a, const void* b) {
+    const char *sa = *(const char **)a;
+    const char *sb = *(const char **)b;
+    return strcmp(sa, sb);
+}
+
+/* sort the strings in a given list (using strcmp) */
+void strlist_sort( strlist_t *list ) {
+    if (list->count > 0) {
+        qsort(list->items, (size_t)list->count, sizeof(void*), strlist_compare_strings);
+    }
+}
+
 
 // bits for flags argument
 #define LIST_LONG           (1 << 0)
@@ -200,7 +296,7 @@
     case S_IFCHR:
         printf("%s %-8s %-8s %3d, %3d %s %s\n",
                mode, user, group,
-               (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
+               major(s->st_rdev), minor(s->st_rdev),
                date, name);
         break;
     case S_IFREG:
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
deleted file mode 100644
index cb5799e..0000000
--- a/toolbox/restorecon.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <selinux/android.h>
-
-static const char *progname;
-
-static void usage(void)
-{
-    fprintf(stderr, "usage:  %s [-DFnrRv] pathname...\n", progname);
-    exit(1);
-}
-
-int restorecon_main(int argc, char **argv)
-{
-    int ch, i, rc;
-    unsigned int flags = 0;
-
-    progname = argv[0];
-
-    do {
-        ch = getopt(argc, argv, "DFnrRv");
-        if (ch == EOF)
-            break;
-        switch (ch) {
-        case 'D':
-            flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
-            break;
-        case 'F':
-            flags |= SELINUX_ANDROID_RESTORECON_FORCE;
-            break;
-        case 'n':
-            flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE;
-            break;
-        case 'r':
-        case 'R':
-            flags |= SELINUX_ANDROID_RESTORECON_RECURSE;
-            break;
-        case 'v':
-            flags |= SELINUX_ANDROID_RESTORECON_VERBOSE;
-            break;
-        default:
-            usage();
-        }
-    } while (1);
-
-    argc -= optind;
-    argv += optind;
-    if (!argc)
-        usage();
-
-    for (i = 0; i < argc; i++) {
-        rc = selinux_android_restorecon(argv[i], flags);
-        if (rc < 0)
-            fprintf(stderr, "Could not restorecon %s:  %s\n", argv[i],
-                    strerror(errno));
-    }
-
-    return 0;
-}
diff --git a/toolbox/setprop.c b/toolbox/setprop.c
deleted file mode 100644
index 63ad2b4..0000000
--- a/toolbox/setprop.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stdio.h>
-
-#include <cutils/properties.h>
-
-int setprop_main(int argc, char *argv[])
-{
-    if(argc != 3) {
-        fprintf(stderr,"usage: setprop <key> <value>\n");
-        return 1;
-    }
-
-    if(property_set(argv[1], argv[2])){
-        fprintf(stderr,"could not set property\n");
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/toolbox/umount.c b/toolbox/umount.c
deleted file mode 100644
index 3e17396..0000000
--- a/toolbox/umount.c
+++ /dev/null
@@ -1,90 +0,0 @@
-
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <linux/loop.h>
-#include <errno.h>
-
-#define LOOPDEV_MAXLEN 64
-#define LOOP_MAJOR 7
-
-static int is_loop(char *dev)
-{
-    struct stat st;
-    int ret = 0;
-
-    if (stat(dev, &st) == 0) {
-        if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
-            ret = 1;
-        }
-    }
-
-    return ret;
-}
-
-static int is_loop_mount(const char* path, char *loopdev)
-{
-    FILE* f;
-    int count;
-    char device[256];
-    char mount_path[256];
-    char rest[256];
-    int result = 0;
-    
-    f = fopen("/proc/mounts", "r");
-    if (!f) {
-        fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno));
-        return -1;
-    }
-
-    do {
-        count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
-        if (count == 3) {
-            if (is_loop(device) && strcmp(path, mount_path) == 0) {
-                strlcpy(loopdev, device, LOOPDEV_MAXLEN);
-                result = 1;
-                break;
-            }
-        }
-    } while (count == 3);
-
-    fclose(f);
-    return result;
-}
-
-int umount_main(int argc, char *argv[])
-{
-    int loop, loop_fd;
-    char loopdev[LOOPDEV_MAXLEN];
-
-    if(argc != 2) {
-        fprintf(stderr,"umount <path>\n");
-        return 1;
-    }
-
-    loop = is_loop_mount(argv[1], loopdev);
-    if (umount(argv[1])) {
-        fprintf(stderr, "failed: %s\n", strerror(errno));
-        return 1;
-    }
-
-    if (loop) {
-        // free the loop device
-        loop_fd = open(loopdev, O_RDONLY);
-        if (loop_fd < 0) {
-            fprintf(stderr, "open loop device failed: %s\n", strerror(errno));
-            return 1;
-        }
-        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
-            fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno));
-            return 1;
-        }
-
-        close(loop_fd);
-    }
-
-    return 0;
-}
diff --git a/tzdatacheck/Android.mk b/tzdatacheck/Android.mk
new file mode 100644
index 0000000..0e25f7d
--- /dev/null
+++ b/tzdatacheck/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# ========================================================
+# Executable
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= tzdatacheck.cpp
+LOCAL_MODULE := tzdatacheck
+LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
+LOCAL_CFLAGS := -Werror
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= tzdatacheck.cpp
+LOCAL_MODULE := tzdatacheck
+LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
+LOCAL_CFLAGS := -Werror
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
new file mode 100644
index 0000000..31f7b55
--- /dev/null
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <ftw.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+
+static const char* TZDATA_FILENAME = "/tzdata";
+// tzdata file header (as much as we need for the version):
+// byte[11] tzdata_version  -- e.g. "tzdata2012f"
+static const int TZ_HEADER_LENGTH = 11;
+
+static void usage() {
+    std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
+            "\n"
+            "Compares the headers of two tzdata files. If the one in SYSTEM_TZ_DIR is the\n"
+            "same or a higher version than the one in DATA_TZ_DIR the DATA_TZ_DIR is renamed\n"
+            "and then deleted.\n";
+    exit(1);
+}
+
+/*
+ * Opens a file and fills headerBytes with the first byteCount bytes from the file. It is a fatal
+ * error if the file is too small or cannot be opened. If the file does not exist false is returned.
+ * If the bytes were read successfully then true is returned.
+ */
+static bool readHeader(const std::string& tzDataFileName, char* headerBytes, size_t byteCount) {
+    FILE* tzDataFile = fopen(tzDataFileName.c_str(), "r");
+    if (tzDataFile == nullptr) {
+        if (errno == ENOENT) {
+            return false;
+        } else {
+            PLOG(FATAL) << "Error opening tzdata file " << tzDataFileName;
+        }
+    }
+    size_t bytesRead = fread(headerBytes, 1, byteCount, tzDataFile);
+    if (bytesRead != byteCount) {
+        LOG(FATAL) << tzDataFileName << " is too small. " << byteCount << " bytes required";
+    }
+    fclose(tzDataFile);
+    return true;
+}
+
+/* Checks the contents of headerBytes. It is a fatal error if it not a tzdata header. */
+static void checkValidHeader(const std::string& fileName, char* headerBytes) {
+    if (strncmp("tzdata", headerBytes, 6) != 0) {
+        LOG(FATAL) << fileName << " does not start with the expected bytes (tzdata)";
+    }
+}
+
+/* Return the parent directory of dirName. */
+static std::string getParentDir(const std::string& dirName) {
+    std::unique_ptr<char> mutable_dirname(strdup(dirName.c_str()));
+    return dirname(mutable_dirname.get());
+}
+
+/* Deletes a single file, symlink or directory. Called from nftw(). */
+static int deleteFn(const char* fpath, const struct stat*, int typeflag, struct FTW*) {
+    LOG(DEBUG) << "Inspecting " << fpath;
+    switch (typeflag) {
+    case FTW_F:
+    case FTW_SL:
+        LOG(DEBUG) << "Unlinking " << fpath;
+        if (unlink(fpath)) {
+            PLOG(WARNING) << "Failed to unlink file/symlink " << fpath;
+        }
+        break;
+    case FTW_D:
+    case FTW_DP:
+        LOG(DEBUG) << "Removing dir " << fpath;
+        if (rmdir(fpath)) {
+            PLOG(WARNING) << "Failed to remove dir " << fpath;
+        }
+        break;
+    default:
+        LOG(WARNING) << "Unsupported file type " << fpath << ": " << typeflag;
+        break;
+    }
+    return 0;
+}
+
+/*
+ * Deletes dirToDelete and returns true if it is successful in removing or moving the directory out
+ * of the way. If dirToDelete does not exist this function does nothing and returns true.
+ *
+ * During deletion, this function first renames the directory to a temporary name. If the temporary
+ * directory cannot be created, or the directory cannot be renamed, false is returned. After the
+ * rename, deletion of files and subdirs beneath the directory is performed on a "best effort"
+ * basis. Symlinks beneath the directory are not followed.
+ */
+static bool deleteDir(const std::string& dirToDelete) {
+    // Check whether the dir exists.
+    struct stat buf;
+    if (stat(dirToDelete.c_str(), &buf) == 0) {
+      if (!S_ISDIR(buf.st_mode)) {
+        LOG(WARNING) << dirToDelete << " is not a directory";
+        return false;
+      }
+    } else {
+      if (errno == ENOENT) {
+          PLOG(INFO) << "Directory does not exist: " << dirToDelete;
+          return true;
+      } else {
+          PLOG(WARNING) << "Unable to stat " << dirToDelete;
+          return false;
+      }
+    }
+
+    // First, rename dirToDelete.
+    std::string tempDirNameTemplate = getParentDir(dirToDelete);
+    tempDirNameTemplate += "/tempXXXXXX";
+
+    // Create an empty directory with the temporary name. For this we need a non-const char*.
+    std::vector<char> tempDirName(tempDirNameTemplate.length() + 1);
+    strcpy(&tempDirName[0], tempDirNameTemplate.c_str());
+    if (mkdtemp(&tempDirName[0]) == nullptr) {
+        PLOG(WARNING) << "Unable to create a temporary directory: " << tempDirNameTemplate;
+        return false;
+    }
+
+    // Rename dirToDelete to tempDirName.
+    int rc = rename(dirToDelete.c_str(), &tempDirName[0]);
+    if (rc == -1) {
+        PLOG(WARNING) << "Unable to rename directory from " << dirToDelete << " to "
+                << &tempDirName[0];
+        return false;
+    }
+
+    // Recursively delete contents of tempDirName.
+    rc = nftw(&tempDirName[0], deleteFn, 10 /* openFiles */,
+            FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
+    if (rc == -1) {
+        LOG(INFO) << "Could not delete directory: " << &tempDirName[0];
+    }
+    return true;
+}
+
+/*
+ * After a platform update it is likely that timezone data found on the system partition will be
+ * newer than the version found in the data partition. This tool detects this case and removes the
+ * version in /data along with any update metadata.
+ *
+ * Note: This code is related to code in com.android.server.updates.TzDataInstallReceiver. The
+ * paths for the metadata and current timezone data must match.
+ *
+ * Typically on device the two args will be:
+ *   /system/usr/share/zoneinfo /data/misc/zoneinfo
+ *
+ * See usage() for usage notes.
+ */
+int main(int argc, char* argv[]) {
+    if (argc != 3) {
+        usage();
+    }
+
+    const char* systemZoneInfoDir = argv[1];
+    const char* dataZoneInfoDir = argv[2];
+
+    std::string dataCurrentDirName(dataZoneInfoDir);
+    dataCurrentDirName += "/current";
+    std::string dataTzDataFileName(dataCurrentDirName);
+    dataTzDataFileName += TZDATA_FILENAME;
+
+    std::vector<char> dataTzDataHeader;
+    dataTzDataHeader.reserve(TZ_HEADER_LENGTH);
+
+    bool dataFileExists = readHeader(dataTzDataFileName, dataTzDataHeader.data(), TZ_HEADER_LENGTH);
+    if (!dataFileExists) {
+        LOG(INFO) << "tzdata file " << dataTzDataFileName << " does not exist. No action required.";
+        return 0;
+    }
+    checkValidHeader(dataTzDataFileName, dataTzDataHeader.data());
+
+    std::string systemTzDataFileName(systemZoneInfoDir);
+    systemTzDataFileName += TZDATA_FILENAME;
+    std::vector<char> systemTzDataHeader;
+    systemTzDataHeader.reserve(TZ_HEADER_LENGTH);
+    bool systemFileExists =
+            readHeader(systemTzDataFileName, systemTzDataHeader.data(), TZ_HEADER_LENGTH);
+    if (!systemFileExists) {
+        LOG(FATAL) << systemTzDataFileName << " does not exist or could not be opened";
+    }
+    checkValidHeader(systemTzDataFileName, systemTzDataHeader.data());
+
+    if (strncmp(&systemTzDataHeader[0], &dataTzDataHeader[0], TZ_HEADER_LENGTH) < 0) {
+        LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the newer than "
+                << systemTzDataFileName << ". No action required.";
+    } else {
+        // We have detected the case this tool is intended to prevent. Go fix it.
+        LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the same as or older than "
+                << systemTzDataFileName << "; fixing...";
+
+        // Delete the update metadata
+        std::string dataUpdatesDirName(dataZoneInfoDir);
+        dataUpdatesDirName += "/updates";
+        LOG(INFO) << "Removing: " << dataUpdatesDirName;
+        bool deleted = deleteDir(dataUpdatesDirName);
+        if (!deleted) {
+            LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
+                    << " was not successful";
+        }
+
+        // Delete the TZ data
+        LOG(INFO) << "Removing: " << dataCurrentDirName;
+        deleted = deleteDir(dataCurrentDirName);
+        if (!deleted) {
+            LOG(WARNING) << "Deletion of tzdata " << dataCurrentDirName << " was not successful";
+        }
+    }
+
+    return 0;
+}