logd: Add klogd

- Add a klogd to collect the kernel logs and place them into a
  new kernel log buffer
- Parse priority, tag and message from the kernel log messages.
- Turn off pruning for worst UID for the kernel log buffer
- Sniff for 'PM: suspend exit', 'PM: suspend enter' and
  'Suspended for' messages and correct the internal definition
  time correction against monotonic dynamically.
- Discern if we have monotonic or real time (delineation 1980) in
  audit messages.
- perform appropriate math to correct the timestamp to be real time
- filter out any external sources of kernel logging

Change-Id: I8d4c7c5ac19f1f3218079ee3a05a50e2ca55f60d
diff --git a/logd/main.cpp b/logd/main.cpp
index 7b8e94e..6db819e 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -42,6 +42,7 @@
 #include "LogBuffer.h"
 #include "LogListener.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
 
 #define KMSG_PRIORITY(PRI)                            \
     '<',                                              \
@@ -256,6 +257,17 @@
     return android_lookupEventTag(map, tag);
 }
 
+static bool property_get_bool_svelte(const char *key) {
+    bool not_user;
+    {
+        char property[PROPERTY_VALUE_MAX];
+        property_get("ro.build.type", property, "");
+        not_user = !!strcmp(property, "user");
+    }
+    return property_get_bool(key, not_user
+            && !property_get_bool("ro.config.low_ram", false));
+}
+
 // 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
@@ -263,6 +275,11 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char *argv[]) {
+    int fdPmesg = -1;
+    bool klogd = property_get_bool_svelte("logd.klogd");
+    if (klogd) {
+        fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
+    }
     fdDmesg = open("/dev/kmsg", O_WRONLY);
 
     // issue reinit command. KISS argument parsing.
@@ -339,14 +356,8 @@
 
     signal(SIGHUP, reinit_signal_handler);
 
-    {
-        char property[PROPERTY_VALUE_MAX];
-        property_get("ro.build.type", property, "");
-        if (property_get_bool("logd.statistics",
-                   !!strcmp(property, "user")
-                && !property_get_bool("ro.config.low_ram", false))) {
-            logBuf->enableStatistics();
-        }
+    if (property_get_bool_svelte("logd.statistics")) {
+        logBuf->enableStatistics();
     }
 
     // LogReader listens on /dev/socket/logdr. When a client
@@ -381,12 +392,18 @@
 
     bool auditd = property_get_bool("logd.auditd", true);
 
+    LogAudit *al = NULL;
     if (auditd) {
         bool dmesg = property_get_bool("logd.auditd.dmesg", true);
+        al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+    }
 
-        // failure is an option ... messages are in dmesg (required by standard)
-        LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+    LogKlog *kl = NULL;
+    if (klogd) {
+        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
+    }
 
+    if (al || kl) {
         int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
         if (len > 0) {
             len++;
@@ -394,16 +411,31 @@
 
             int rc = klogctl(KLOG_READ_ALL, buf, len);
 
-            if (rc >= 0) {
-                buf[len - 1] = '\0';
+            buf[len - 1] = '\0';
 
-                for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) {
-                    al->log(tok);
+            if ((rc >= 0) && kl) {
+                kl->synchronize(buf);
+            }
+
+            for (char *ptr, *tok = buf;
+                 (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
+                 tok = NULL) {
+                if (al) {
+                    rc = al->log(tok);
+                }
+                if (kl) {
+                    rc = kl->log(tok);
                 }
             }
         }
 
-        if (al->startListener()) {
+        // failure is an option ... messages are in dmesg (required by standard)
+
+        if (kl && kl->startListener()) {
+            delete kl;
+        }
+
+        if (al && al->startListener()) {
             delete al;
         }
     }