Merge "liblog: logd: Add android_lookupEventTag_len()" am: 093951a230 am: aed39f1f3d am: 2acb41b46c
am: 96eba22338

Change-Id: I5321bf766ac59f0ecc34bb3623440621a6a7ab1d
diff --git a/include/android/log.h b/include/android/log.h
index de5502a..5f20f8c 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -803,10 +803,12 @@
  */
 #if LOG_NDEBUG /* Production */
 #define android_testLog(prio, tag) \
-    (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
+    (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+                                   ANDROID_LOG_DEBUG) != 0)
 #else
 #define android_testLog(prio, tag) \
-    (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
+    (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+                                   ANDROID_LOG_VERBOSE) != 0)
 #endif
 
 /*
@@ -816,6 +818,7 @@
  * any other value.
  */
 int __android_log_is_loggable(int prio, const char *tag, int default_prio);
+int __android_log_is_loggable_len(int prio, const char *tag, size_t len, int default_prio);
 
 int __android_log_security(); /* Device Owner is present */
 
diff --git a/include/log/event_tag_map.h b/include/log/event_tag_map.h
index 7ee0a7c..69774ba 100644
--- a/include/log/event_tag_map.h
+++ b/include/log/event_tag_map.h
@@ -41,7 +41,14 @@
 /*
  * Look up a tag by index.  Returns the tag string, or NULL if not found.
  */
-const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag);
+const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag)
+    __attribute__((deprecated("use android_lookupEventTag_len() instead to minimize MAP_PRIVATE copy-on-write memory impact")));
+
+/*
+ * Look up a tag by index.  Returns the tag string & string length, or NULL if
+ * not found.  Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag);
 
 #ifdef __cplusplus
 }
diff --git a/include/log/logprint.h b/include/log/logprint.h
index b8d8d4c..f70633d 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -59,6 +59,7 @@
     int32_t pid;
     int32_t tid;
     const char * tag;
+    size_t tagLen;
     size_t messageLen;
     const char * message;
 } AndroidLogEntry;
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index c2dc74c..6705fb2 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -34,8 +34,9 @@
  * Single entry.
  */
 typedef struct EventTag {
-    uint32_t    tagIndex;
-    const char* tagStr;
+    uint32_t tagIndex;
+    char*    tagStr;
+    size_t   tagLen;
 } EventTag;
 
 /*
@@ -139,8 +140,9 @@
  *
  * The entries are sorted by tag number, so we can do a binary search.
  */
-LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
-                                                     unsigned int tag)
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
+                                                         size_t *len,
+                                                         unsigned int tag)
 {
     int lo = 0;
     int hi = map->numTags - 1;
@@ -157,14 +159,36 @@
             hi = mid - 1;
         } else {
             /* found */
+            if (len) *len = map->tagArray[mid].tagLen;
+            /*
+             * b/31456426 to check if gTest can detect copy-on-write issue
+             * add the following line to break us:
+             *     map->tagArray[mid].tagStr[map->tagArray[mid].tagLen] = '\0';
+             * or explicitly use deprecated android_lookupEventTag().
+             */
             return map->tagArray[mid].tagStr;
         }
     }
 
     errno = ENOENT;
+    if (len) *len = 0;
     return NULL;
 }
 
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
+                                                     unsigned int tag)
+{
+    size_t len;
+    const char* tagStr = android_lookupEventTag_len(map, &len, tag);
+    char* cp;
+
+    if (!tagStr) return tagStr;
+    cp = (char*)tagStr;
+    cp += len;
+    if (*cp) *cp = '\0'; /* Trigger copy on write :-( */
+    return tagStr;
+}
+
 /*
  * Crunch through the file, parsing the contents and creating a tag index.
  */
@@ -337,19 +361,13 @@
     /* Determine whether "c" is a valid tag char. */
     while (isalnum(*++cp) || (*cp == '_')) {
     }
+    tag->tagLen = cp - tag->tagStr;
 
-    if (*cp == '\n') {
-        /* null terminate and return */
-        *cp = '\0';
-    } else if (isspace(*cp)) {
-        /* CRLF or trailin spaces; zap this char, then scan for the '\n' */
-        *cp = '\0';
-
+    if (isspace(*cp)) {
         /* just ignore the rest of the line till \n
         TODO: read the tag description that follows the tag name
         */
-        while (*++cp != '\n') {
-        }
+        while (*cp != '\n') ++cp;
     } else {
         fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
         errno = EINVAL;
@@ -387,10 +405,12 @@
     for (i = 1; i < map->numTags; i++) {
         if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
             fprintf(stderr,
-                "%s: duplicate tag entries (%" PRIu32 ":%s and %" PRIu32 ":%s)\n",
+                "%s: duplicate tag entries (%" PRIu32 ":%.*s and %" PRIu32 ":%.*s)\n",
                 OUT_TAG,
-                map->tagArray[i].tagIndex, map->tagArray[i].tagStr,
-                map->tagArray[i - 1].tagIndex, map->tagArray[i - 1].tagStr);
+                map->tagArray[i].tagIndex, (int)map->tagArray[i].tagLen,
+                map->tagArray[i].tagStr,
+                map->tagArray[i - 1].tagIndex, (int)map->tagArray[i - 1].tagLen,
+                map->tagArray[i - 1].tagStr);
             errno = EMLINK;
             return -1;
         }
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 1b57e75..7bd1f83 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -718,3 +718,12 @@
     int logLevel = def;
     return logLevel >= 0 && prio >= logLevel;
 }
+
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
+                                                    const char *tag __unused,
+                                                    size_t len __unused,
+                                                    int def)
+{
+    int logLevel = def;
+    return logLevel >= 0 && prio >= logLevel;
+}
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index bd8d5af..4af8507 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -85,13 +85,13 @@
     }
 }
 
-static int __android_log_level(const char *tag, int default_prio)
+static int __android_log_level(const char *tag, size_t len, int default_prio)
 {
     /* sizeof() is used on this array below */
     static const char log_namespace[] = "persist.log.tag.";
     static const size_t base_offset = 8; /* skip "persist." */
     /* calculate the size of our key temporary buffer */
-    const size_t taglen = (tag && *tag) ? strlen(tag) : 0;
+    const size_t taglen = tag ? len : 0;
     /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
     char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */
     char *kp;
@@ -147,7 +147,11 @@
         if (!not_locked) {
             if (!last_tag[0]
                     || (last_tag[0] != tag[0])
-                    || strncmp(last_tag + 1, tag + 1, sizeof(last_tag) - 1)) {
+                    || strncmp(last_tag + 1, tag + 1,
+                               (len < sizeof(last_tag)) ?
+                                    (len - 1) :
+                                    (sizeof(last_tag) - 1))
+                    || ((len < sizeof(last_tag)) && last_tag[len])) {
                 /* invalidate log.tag.<tag> cache */
                 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
                     tag_cache[i].pinfo = NULL;
@@ -157,10 +161,16 @@
                 local_change_detected = 1;
             }
             if (!last_tag[0]) {
-                strncpy(last_tag, tag, sizeof(last_tag));
+                if (len < sizeof(last_tag)) {
+                    strncpy(last_tag, tag, len);
+                    last_tag[len] = '\0';
+                } else {
+                    strncpy(last_tag, tag, sizeof(last_tag));
+                }
             }
         }
-        strcpy(key + sizeof(log_namespace) - 1, tag);
+        strncpy(key + sizeof(log_namespace) - 1, tag, len);
+        key[sizeof(log_namespace) - 1 + len] = '\0';
 
         kp = key;
         for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
@@ -246,10 +256,21 @@
     return default_prio;
 }
 
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char *tag,
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
+                                                    const char *tag, size_t len,
+                                                    int default_prio)
+{
+    int logLevel = __android_log_level(tag, len, default_prio);
+    return logLevel >= 0 && prio >= logLevel;
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
+                                                const char *tag,
                                                 int default_prio)
 {
-    int logLevel = __android_log_level(tag, default_prio);
+    int logLevel = __android_log_level(tag,
+                                       (tag && *tag) ? strlen(tag) : 0,
+                                       default_prio);
     return logLevel >= 0 && prio >= logLevel;
 }
 
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index ebf8b3e..e8e392d 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -181,9 +181,9 @@
             }
         }
         snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-        if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
-                                                  "liblog",
-                                                  ANDROID_LOG_VERBOSE)) {
+        if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO,
+                                                      "liblog", strlen("liblog"),
+                                                      ANDROID_LOG_VERBOSE)) {
             android_log_event_int_t buffer;
 
             header.id = LOG_ID_EVENTS;
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 4999aef..1e56b27 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -279,6 +279,7 @@
         }
     } else if (log_id == LOG_ID_EVENTS) {
         const char *tag;
+        size_t len;
         EventTagMap *m, *f;
 
         if (vec[0].iov_len < 4) {
@@ -286,6 +287,7 @@
         }
 
         tag = NULL;
+        len = 0;
         f = NULL;
         m = (EventTagMap *)atomic_load(&tagMap);
 
@@ -308,11 +310,11 @@
             }
         }
         if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
-            tag = android_lookupEventTag(m, get4LE(vec[0].iov_base));
+            tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
         }
-        ret = __android_log_is_loggable(ANDROID_LOG_INFO,
-                                        tag,
-                                        ANDROID_LOG_VERBOSE);
+        ret = __android_log_is_loggable_len(ANDROID_LOG_INFO,
+                                            tag, len,
+                                            ANDROID_LOG_VERBOSE);
         if (f) { /* local copy marked for close */
             android_closeEventTagMap(f);
         }
@@ -345,7 +347,9 @@
             tag = NULL;
         }
 
-        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+        if (!__android_log_is_loggable_len(prio,
+                                           tag, len - 1,
+                                           ANDROID_LOG_VERBOSE)) {
             return -EPERM;
         }
     }
diff --git a/liblog/logprint.c b/liblog/logprint.c
index d857090..2c4e619 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -539,6 +539,7 @@
 
     entry->priority = msg[0];
     entry->tag = msg + 1;
+    entry->tagLen = msgStart - 1;
     entry->message = msg + msgStart;
     entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
 
@@ -801,8 +802,9 @@
     eventData += 4;
     inCount -= 4;
 
+    entry->tagLen = 0;
     if (map != NULL) {
-        entry->tag = android_lookupEventTag(map, tagIndex);
+        entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
     } else {
         entry->tag = NULL;
     }
@@ -813,12 +815,16 @@
      * shift the buffer pointers down.
      */
     if (entry->tag == NULL) {
-        int tagLen;
+        size_t tagLen;
 
         tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
+        if (tagLen >= (size_t)messageBufLen) {
+            tagLen = messageBufLen - 1;
+        }
         entry->tag = messageBuf;
-        messageBuf += tagLen+1;
-        messageBufLen -= tagLen+1;
+        entry->tagLen = tagLen;
+        messageBuf += tagLen + 1;
+        messageBufLen -= tagLen + 1;
     }
 
     /*
@@ -1386,13 +1392,13 @@
     switch (p_format->format) {
         case FORMAT_TAG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c/%-8s: ", priChar, entry->tag);
+                "%c/%-8.*s: ", priChar, (int)entry->tagLen, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_PROCESS:
             len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
-                "  (%s)\n", entry->tag);
+                "  (%.*s)\n", (int)entry->tagLen, entry->tag);
             suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
                 "%c(%s%5d) ", priChar, uid, entry->pid);
@@ -1411,8 +1417,8 @@
             break;
         case FORMAT_TIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %c/%-8s(%s%5d): ", timeBuf, priChar, entry->tag,
-                uid, entry->pid);
+                "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar,
+                (int)entry->tagLen, entry->tag, uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
@@ -1422,15 +1428,16 @@
                 *ret = ' ';
             }
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %s%5d %5d %c %-8s: ", timeBuf,
-                uid, entry->pid, entry->tid, priChar, entry->tag);
+                "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid,
+                entry->tid, priChar, (int)entry->tagLen, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_LONG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "[ %s %s%5d:%5d %c/%-8s ]\n",
-                timeBuf, uid, entry->pid, entry->tid, priChar, entry->tag);
+                "[ %s %s%5d:%5d %c/%-8.*s ]\n",
+                timeBuf, uid, entry->pid, entry->tid, priChar,
+                (int)entry->tagLen, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n\n");
             suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
@@ -1438,7 +1445,8 @@
         case FORMAT_BRIEF:
         default:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c/%-8s(%s%5d): ", priChar, entry->tag, uid, entry->pid);
+                "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen, entry->tag,
+                uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 8229859..a755b98 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -40,7 +40,7 @@
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(benchmark_c_flags)
-LOCAL_SHARED_LIBRARIES += liblog libm
+LOCAL_SHARED_LIBRARIES += liblog libm libbase
 LOCAL_SRC_FILES := $(benchmark_src_files)
 include $(BUILD_NATIVE_TEST)
 
@@ -73,6 +73,6 @@
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 7561d8f..cd012ce 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -650,10 +650,14 @@
  *	Measure the time it takes for __android_log_is_loggable.
  */
 static void BM_is_loggable(int iters) {
+    static const char logd[] = "logd";
+
     StartBenchmarkTiming();
 
     for (int i = 0; i < iters; ++i) {
-        __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE);
+        __android_log_is_loggable_len(ANDROID_LOG_WARN,
+                                      logd, strlen(logd),
+                                      ANDROID_LOG_VERBOSE);
     }
 
     StopBenchmarkTiming();
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 6e709a9..b1dae9e 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <dirent.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <semaphore.h>
@@ -22,7 +24,11 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <string>
+
 #include <android/log.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 #include <log/logger.h>
@@ -1337,8 +1343,8 @@
                 continue;
             }
             fprintf(stderr, "i=%zu j=%zu\r", i, j);
-            bool android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, levels[j].level);
+            bool android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), levels[j].level);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)) {
                 if (android_log_is_loggable) {
@@ -1346,8 +1352,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, levels[j].level));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), levels[j].level));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1355,8 +1361,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, levels[j].level));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), levels[j].level));
                 }
             }
         }
@@ -1377,8 +1383,8 @@
                     i, j, key, buf);
             usleep(20000);
             property_set(key, buf);
-            bool android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            bool android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1388,8 +1394,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1397,8 +1403,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
             usleep(20000);
@@ -1407,8 +1413,8 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1418,8 +1424,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1427,8 +1433,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
             usleep(20000);
@@ -1439,8 +1445,8 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
             property_set(key, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1450,8 +1456,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1459,8 +1465,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
             usleep(20000);
@@ -1469,8 +1475,8 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1480,8 +1486,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1489,8 +1495,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
             usleep(20000);
@@ -1517,8 +1523,8 @@
                     i, j, key, buf);
             usleep(20000);
             property_set(key, buf);
-            bool android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            bool android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
@@ -1528,8 +1534,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1537,8 +1543,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
             usleep(20000);
@@ -1547,8 +1553,8 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
@@ -1558,8 +1564,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1567,8 +1573,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
             usleep(20000);
@@ -2617,3 +2623,83 @@
     EXPECT_LT(0, ret);
     EXPECT_EQ(1U, signaled);
 }
+
+// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
+static testing::AssertionResult IsOk(bool ok, std::string &message) {
+    return ok ?
+        testing::AssertionSuccess() :
+        (testing::AssertionFailure() << message);
+}
+
+static void event_log_tags_test_smap(pid_t pid) {
+    std::string filename = android::base::StringPrintf("/proc/%d/smaps", pid);
+
+    std::string content;
+    if (!android::base::ReadFileToString(filename, &content)) return;
+
+    bool shared_ok = false;
+    bool anonymous_ok = false;
+    bool pass_ok = false;
+
+    static const char event_log_tags[] = "event-log-tags";
+    std::string::size_type pos = 0;
+    while ((pos = content.find(event_log_tags, pos)) != std::string::npos) {
+        pos += strlen(event_log_tags);
+
+        // must not be: 'Shared_Clean: 0 kB'
+        static const char shared_clean[] = "Shared_Clean:";
+        std::string::size_type clean = content.find(shared_clean, pos);
+        bool ok = (clean != std::string::npos) &&
+                  ((clean = content.find_first_not_of(" \t", clean +
+                                strlen(shared_clean))) != std::string::npos) &&
+                  (content.find_first_not_of("123456789", clean) != clean);
+        if (ok && !pass_ok) {
+            shared_ok = true;
+        } else if (!ok) {
+            shared_ok = false;
+        }
+
+        // must be: 'Anonymous: 0 kB'
+        static const char anonymous[] = "Anonymous:";
+        std::string::size_type anon = content.find(anonymous, pos);
+        ok = (anon != std::string::npos) &&
+             ((anon = content.find_first_not_of(" \t", anon +
+                          strlen(anonymous))) != std::string::npos) &&
+             (content.find_first_not_of("0", anon) != anon);
+        if (ok && !pass_ok) {
+            anonymous_ok = true;
+        } else if (!ok) {
+            anonymous_ok = false;
+        }
+
+        pass_ok = true;
+    }
+    content = "";
+
+    if (!pass_ok) return;
+    if (shared_ok && anonymous_ok) return;
+
+    filename = android::base::StringPrintf("/proc/%d/comm", pid);
+    android::base::ReadFileToString(filename, &content);
+    content = android::base::StringPrintf("%d:%s",
+                  pid, content.substr(0, content.find("\n")).c_str());
+
+    EXPECT_TRUE(IsOk(shared_ok, content));
+    EXPECT_TRUE(IsOk(anonymous_ok, content));
+}
+
+TEST(liblog, event_log_tags) {
+    std::unique_ptr<DIR, int(*)(DIR*)> proc_dir(opendir("/proc"), closedir);
+    ASSERT_FALSE(!proc_dir);
+
+    dirent* e;
+    while ((e = readdir(proc_dir.get()))) {
+        if (e->d_type != DT_DIR) continue;
+        if (!isdigit(e->d_name[0])) continue;
+        long long id = atoll(e->d_name);
+        if (id <= 0) continue;
+        pid_t pid = id;
+        if (id != pid) continue;
+        event_log_tags_test_smap(pid);
+    }
+}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1ecf99c..7f5fe4f 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -211,13 +211,15 @@
     if (log_id != LOG_ID_SECURITY) {
         int prio = ANDROID_LOG_INFO;
         const char *tag = NULL;
+        size_t len = 0;
         if (log_id == LOG_ID_EVENTS) {
-            tag = android::tagToName(elem->getTag());
+            tag = android::tagToName(&len, elem->getTag());
         } else {
             prio = *msg;
             tag = msg + 1;
+            len = strlen(tag);
         }
-        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+        if (!__android_log_is_loggable_len(prio, tag, len, ANDROID_LOG_VERBOSE)) {
             // Log traffic received to total
             pthread_mutex_lock(&mLogElementsLock);
             stats.add(elem);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 3e6e586..e5de11d 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -110,7 +110,9 @@
         LogBuffer *parent) {
     static const char tag[] = "chatty";
 
-    if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
+    if (!__android_log_is_loggable_len(ANDROID_LOG_INFO,
+                                       tag, strlen(tag),
+                                       ANDROID_LOG_VERBOSE)) {
         return 0;
     }
 
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 86d33b2..c6ebd52 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -436,11 +436,12 @@
         name = android::base::StringPrintf("%7u/%u",
                                            getKey(), uid);
     }
-    const char *nameTmp = getName();
+    size_t len = 0;
+    const char *nameTmp = getName(len);
     if (nameTmp) {
         name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
-            "", nameTmp);
+            "%*s%.*s", (int)std::max(14 - name.length(), (size_t)1),
+            "", (int)len, nameTmp);
     }
 
     std::string size = android::base::StringPrintf("%zu",
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index e811953..bfaafa4 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -385,7 +385,7 @@
     const uint32_t&getKey() const { return tag; }
     const pid_t&getPid() const { return pid; }
     const uid_t&getUid() const { return uid; }
-    const char*getName() const { return android::tagToName(tag); }
+    const char*getName(size_t &len) const { return android::tagToName(&len, tag); }
 
     inline void add(LogBufferElement *element) {
         if (uid != element->getUid()) {
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 939515e..6db4c51 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -37,7 +37,7 @@
 char *tidToName(pid_t tid);
 
 // Furnished in main.cpp. Thread safe.
-const char *tagToName(uint32_t tag);
+const char *tagToName(size_t *len, uint32_t tag);
 
 }
 
diff --git a/logd/main.cpp b/logd/main.cpp
index 77a6973..a0cea25 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -302,7 +302,7 @@
 }
 
 // tagToName converts an events tag into a name
-const char *android::tagToName(uint32_t tag) {
+const char *android::tagToName(size_t *len, uint32_t tag) {
     static const EventTagMap *map;
 
     if (!map) {
@@ -312,10 +312,11 @@
         }
         sem_post(&sem_name);
         if (!map) {
+            if (len) len = 0;
             return NULL;
         }
     }
-    return android_lookupEventTag(map, tag);
+    return android_lookupEventTag_len(map, len, tag);
 }
 
 static void readDmesg(LogAudit *al, LogKlog *kl) {