Merge "liblog: event log tags cache miss call logd for update"
am: 364bf6db00

Change-Id: Iec62a14af4d213caf4a26b838c8d5e74edb898be
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 1f08eb4..42f0f37 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -227,19 +227,30 @@
 // successful return, it will be pointing to the last character in the
 // tag line (i.e. the character before the start of the next line).
 //
+// lineNum = 0 removes verbose comments and requires us to cache the
+// content rather than make direct raw references since the content
+// will disappear after the call. A non-zero lineNum means we own the
+// data and it will outlive the call.
+//
 // Returns 0 on success, nonzero on failure.
 static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
     char* cp;
     unsigned long val = strtoul(*pData, &cp, 10);
     if (cp == *pData) {
-        fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
+        if (lineNum) {
+            fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n",
+                    lineNum);
+        }
         errno = EINVAL;
         return -1;
     }
 
     uint32_t tagIndex = val;
     if (tagIndex != val) {
-        fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
+        if (lineNum) {
+            fprintf(stderr, OUT_TAG ": tag number too large on line %d\n",
+                    lineNum);
+        }
         errno = ERANGE;
         return -1;
     }
@@ -248,7 +259,10 @@
     }
 
     if (*cp == '\n') {
-        fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
+        if (lineNum) {
+            fprintf(stderr, OUT_TAG ": missing tag string on line %d\n",
+                    lineNum);
+        }
         errno = EINVAL;
         return -1;
     }
@@ -259,7 +273,10 @@
     size_t tagLen = cp - tag;
 
     if (!isspace(*cp)) {
-        fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
+        if (lineNum) {
+            fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n",
+                    lineNum);
+        }
         errno = EINVAL;
         return -1;
     }
@@ -293,9 +310,18 @@
 #endif
     *pData = cp;
 
-    if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
-            MapString(tag, tagLen), MapString(fmt, fmtLen))), verbose)) {
-        return 0;
+    if (lineNum) {
+        if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
+                MapString(tag, tagLen), MapString(fmt, fmtLen))), verbose)) {
+            return 0;
+        }
+    } else {
+        // cache
+        if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
+                MapString(std::string(tag, tagLen)),
+                MapString(std::string(fmt, fmtLen)))))) {
+            return 0;
+        }
     }
     errno = EMLINK;
     return -1;
@@ -455,12 +481,55 @@
     if (map) delete map;
 }
 
+// Cache miss, go to logd to acquire a public reference.
+// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
+static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
+    // call event tag service to arrange for a new tag
+    char *buf = NULL;
+    // Can not use android::base::StringPrintf, asprintf + free instead.
+    static const char command_template[] = "getEventTag id=%u";
+    int ret = asprintf(&buf, command_template, tag);
+    if (ret > 0) {
+        // Add some buffer margin for an estimate of the full return content.
+        char *cp;
+        size_t size = ret - strlen(command_template) +
+            strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
+        if (size > (size_t)ret) {
+            cp = static_cast<char*>(realloc(buf, size));
+            if (cp) {
+                buf = cp;
+            } else {
+                size = ret;
+            }
+        } else {
+            size = ret;
+        }
+        // Ask event log tag service for an existing entry
+        if (__send_log_msg(buf, size) >= 0) {
+            buf[size - 1] = '\0';
+            unsigned long val = strtoul(buf, &cp, 10); // return size
+            if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
+                ++cp;
+                if (!scanTagLine(map, &cp, 0)) {
+                    free(buf);
+                    return map->find(tag);
+                }
+            }
+        }
+        free(buf);
+    }
+    return NULL;
+}
+
 // Look up an entry in the map.
 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
                                                          size_t *len,
                                                          unsigned int tag) {
     if (len) *len = 0;
     const TagFmt* str = map->find(tag);
+    if (!str) {
+        str = __getEventTag(const_cast<EventTagMap*>(map), tag);
+    }
     if (!str) return NULL;
     if (len) *len = str->first.length();
     return str->first.data();
@@ -471,6 +540,9 @@
         const EventTagMap* map, size_t *len, unsigned int tag) {
     if (len) *len = 0;
     const TagFmt* str = map->find(tag);
+    if (!str) {
+        str = __getEventTag(const_cast<EventTagMap*>(map), tag);
+    }
     if (!str) return NULL;
     if (len) *len = str->second.length();
     return str->second.data();