liblog: add pstore write

Used to push the Android log messages into pstore
(when available, and no propagation of error).

Change-Id: I9def8cf796d35d347f502d9745d5f42ec1200253
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 3d847f1..1e9b591 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -62,6 +62,7 @@
 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
 #else
 static int logd_fd = -1;
+static int pstore_fd = -1;
 #endif
 
 /*
@@ -110,6 +111,12 @@
         logd_fd = -1;
         close(i);
     }
+    if (pstore_fd >= 0) {
+        i = pstore_fd;
+        pstore_fd = -1;
+        close(i);
+    }
+    pstore_fd = open("/dev/pmsg0", O_WRONLY);
 
     i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
     if (i < 0) {
@@ -156,32 +163,26 @@
         }
     } while (ret == -EINTR);
 #else
-    static const unsigned header_length = 1;
+    static const unsigned header_length = 2;
     struct iovec newVec[nr + header_length];
-    struct android_log_header_t header;
+    android_log_header_t header;
+    android_pmsg_log_header_t pmsg_header;
     struct timespec ts;
     size_t i, payload_size;
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+    static pid_t last_pid = (pid_t) -1;
 
     if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
         last_uid = getuid();
     }
-    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
-        /*
-         * ignore log messages we send to ourself (logd).
-         * Such log messages are often generated by libraries we depend on
-         * which use standard Android logging.
-         */
-        return 0;
+    if (last_pid == (pid_t) -1) {
+        last_pid = getpid();
     }
-
-    if (logd_fd < 0) {
-        return -EBADF;
-    }
-
     /*
      *  struct {
-     *      // what we provide
+     *      // whate we provire to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
      *      android_log_header_t header;
      *      // caller provides
      *      union {
@@ -199,13 +200,20 @@
 
     clock_gettime(CLOCK_REALTIME, &ts);
 
+    pmsg_header.magic = LOGGER_MAGIC;
+    pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
+    pmsg_header.uid = last_uid;
+    pmsg_header.pid = last_pid;
+
     header.id = log_id;
     header.tid = gettid();
     header.realtime.tv_sec = ts.tv_sec;
     header.realtime.tv_nsec = ts.tv_nsec;
 
-    newVec[0].iov_base   = (unsigned char *) &header;
-    newVec[0].iov_len    = sizeof(header);
+    newVec[0].iov_base   = (unsigned char *) &pmsg_header;
+    newVec[0].iov_len    = sizeof(pmsg_header);
+    newVec[1].iov_base   = (unsigned char *) &header;
+    newVec[1].iov_len    = sizeof(header);
 
     for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
         newVec[i].iov_base = vec[i - header_length].iov_base;
@@ -216,17 +224,38 @@
             if (newVec[i].iov_len) {
                 ++i;
             }
+            payload_size = LOGGER_ENTRY_MAX_PAYLOAD;
             break;
         }
     }
+    pmsg_header.len += payload_size;
+
+    if (pstore_fd >= 0) {
+        TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i));
+    }
+
+    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
+        /*
+         * ignore log messages we send to ourself (logd).
+         * Such log messages are often generated by libraries we depend on
+         * which use standard Android logging.
+         */
+        return 0;
+    }
+
+    if (logd_fd < 0) {
+        return -EBADF;
+    }
 
     /*
      * The write below could be lost, but will never block.
      *
+     * To logd, we drop the pmsg_header
+     *
      * ENOTCONN occurs if logd dies.
      * EAGAIN occurs if logd is overloaded.
      */
-    ret = writev(logd_fd, newVec, i);
+    ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
     if (ret < 0) {
         ret = -errno;
         if (ret == -ENOTCONN) {
@@ -242,7 +271,7 @@
                 return ret;
             }
 
-            ret = writev(logd_fd, newVec, i);
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
             if (ret < 0) {
                 ret = -errno;
             }