merge in mnc-release history after reset to mnc-dev
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 4567b04..735033e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -57,8 +57,14 @@
 
 static int insmod(const char *filename, char *options)
 {
+    char filename_val[PROP_VALUE_MAX];
+    if (expand_props(filename_val, filename, sizeof(filename_val)) == -1) {
+        ERROR("insmod: cannot expand '%s'\n", filename);
+        return -EINVAL;
+    }
+
     std::string module;
-    if (!read_file(filename, &module)) {
+    if (!read_file(filename_val, &module)) {
         return -1;
     }
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index b76b04e..d36995d 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -382,13 +382,13 @@
 
 static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     struct listnode import_list;
     struct listnode *node;
     char *args[INIT_PARSER_MAXARGS];
-    int nargs;
 
-    nargs = 0;
+    int nargs = 0;
+
+    parse_state state;
     state.filename = fn;
     state.line = 0;
     state.ptr = strdup(data.c_str());  // TODO: fix this code!
@@ -444,6 +444,7 @@
         return -1;
     }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(path, data);
     dump_parser_state();
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a52c41d..0ee0351 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -420,6 +420,7 @@
     Timer t;
     std::string data;
     if (read_file(filename, &data)) {
+        data.push_back('\n');
         load_properties(&data[0], filter);
     }
     NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 7a4841f..497c606 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -193,10 +193,10 @@
 
 static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     char *args[UEVENTD_PARSER_MAXARGS];
-    int nargs;
-    nargs = 0;
+
+    int nargs = 0;
+    parse_state state;
     state.filename = fn;
     state.line = 1;
     state.ptr = strdup(data.c_str());  // TODO: fix this code!
@@ -231,6 +231,7 @@
         return -1;
     }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(fn, data);
     dump_parser_state();
     return 0;
diff --git a/init/util.cpp b/init/util.cpp
index d6fd0fc..df4c25f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -171,9 +171,6 @@
 
     bool okay = android::base::ReadFdToString(fd, content);
     TEMP_FAILURE_RETRY(close(fd));
-    if (okay) {
-        content->append("\n", 1);
-    }
     return okay;
 }
 
@@ -475,4 +472,3 @@
         android::base::StringAppendF(&hex, "%02x", bytes[i]);
     return hex;
 }
-
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 6a05700..164faa9 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -50,6 +50,13 @@
     delete [] mMsg;
 }
 
+uint32_t LogBufferElement::getTag() const {
+    if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+        return 0;
+    }
+    return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
+}
+
 // caller must own and free character string
 static char *tidToName(pid_t tid) {
     char *retval = NULL;
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index b6c6196..75ec59e 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -36,6 +36,9 @@
 // Furnished in LogStatistics.cpp. Caller must own and free returned value
 char *pidToName(pid_t pid);
 
+// Furnished in main.cpp. Thread safe.
+const char *tagToName(uint32_t tag);
+
 }
 
 static inline bool worstUidEnabledForLogid(log_id_t id) {
@@ -85,6 +88,8 @@
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
+    uint32_t getTag(void) const;
+
     static const uint64_t FLUSH_ERROR;
     uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
 };
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 10f7255..4511e0b 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -80,6 +80,11 @@
     }
 
     pidTable.add(e->getPid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.add(tag, e);
+    }
 }
 
 void LogStatistics::subtract(LogBufferElement *e) {
@@ -95,6 +100,11 @@
     }
 
     pidTable.subtract(e->getPid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.subtract(tag, e);
+    }
 }
 
 // Atomically set an entry to drop
@@ -131,7 +141,11 @@
     }
 
     // Parse /data/system/packages.list
-    char *name = android::uidToName(uid);
+    uid_t userId = uid % AID_USER;
+    char *name = android::uidToName(userId);
+    if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
+        name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
+    }
     if (name) {
         return name;
     }
@@ -149,7 +163,8 @@
                     name = strdup(n);
                 } else if (strcmp(name, n)) {
                     free(name);
-                    return NULL;
+                    name = NULL;
+                    break;
                 }
             }
         }
@@ -368,6 +383,51 @@
         }
     }
 
+    if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
+        // Tag table
+        bool headerPrinted = false;
+        std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TagEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            android::String8 pruned("");
+
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest events log buffer TAGs:");
+                android::String8 size("Size");
+                format_line(output, name, size, pruned);
+
+                name.setTo("    TAG/UID   TAGNAME");
+                size.setTo("BYTES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            if (u == (uid_t)-1) {
+                name.appendFormat("%7u", entry->getKey());
+            } else {
+                name.appendFormat("%7u/%u", entry->getKey(), u);
+            }
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
     *buf = strdup(output.string());
 }
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index a935c27..d21a75b 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -154,8 +154,6 @@
 };
 
 namespace android {
-// caller must own and free character string
-char *pidToName(pid_t pid);
 uid_t pidToUid(pid_t pid);
 }
 
@@ -186,6 +184,10 @@
     const char*getName() const { return name; }
 
     inline void add(pid_t p) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
         if (!name) {
             char *n = android::pidToName(p);
             if (n) {
@@ -205,7 +207,28 @@
         }
         EntryBaseDropped::add(e);
     }
+};
 
+struct TagEntry : public EntryBase {
+    const uint32_t tag;
+    uid_t uid;
+
+    TagEntry(LogBufferElement *e):
+        EntryBase(e),
+        tag(e->getTag()),
+        uid(e->getUid()) { }
+
+    const uint32_t&getKey() const { return tag; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return android::tagToName(tag); }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (uid != u) {
+            uid = -1;
+        }
+        EntryBase::add(e);
+    }
 };
 
 // Log Statistics
@@ -224,6 +247,10 @@
     typedef LogHashtable<pid_t, PidEntry> pidTable_t;
     pidTable_t pidTable;
 
+    // tag list
+    typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
+    tagTable_t tagTable;
+
 public:
     LogStatistics();
 
diff --git a/logd/main.cpp b/logd/main.cpp
index 237c7c1..7b8e94e 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -35,6 +35,7 @@
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
+#include <log/event_tag_map.h>
 #include <private/android_filesystem_config.h>
 
 #include "CommandListener.h"
@@ -238,6 +239,23 @@
     sem_post(&reinit);
 }
 
+// tagToName converts an events tag into a name
+const char *android::tagToName(uint32_t tag) {
+    static const EventTagMap *map;
+
+    if (!map) {
+        sem_wait(&sem_name);
+        if (!map) {
+            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        }
+        sem_post(&sem_name);
+        if (!map) {
+            return NULL;
+        }
+    }
+    return android_lookupEventTag(map, tag);
+}
+
 // Foreground waits for exit of the main persistent threads
 // that are started here. The threads are created to manage
 // UNIX domain client sockets for writing, reading and