liblog: split out transports into separate files

Create config_logger, logger and logger_read to house the log
interfaces. Add fake_logger, logd_logger and pmsg_logger to
house the write and read transports. Allows for an easier and
direct path to add new transports to the library.

SideEffects: None, logger benchmark performance unaffected

Bug: 27176738
Bug: 27405083
Change-Id: I01b38637334a5242905c8c89f6ab0a92e2540008
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
new file mode 100644
index 0000000..7a89e5d
--- /dev/null
+++ b/liblog/pmsg_writer.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007-2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * pmsg write handler
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static int pmsgOpen();
+static void pmsgClose();
+static int pmsgAvailable(log_id_t logId);
+static int pmsgWrite(log_id_t logId, struct timespec *ts,
+                      struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
+    .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node },
+    .context.fd = -1,
+    .name = "pmsg",
+    .available = pmsgAvailable,
+    .open = pmsgOpen,
+    .close = pmsgClose,
+    .write = pmsgWrite,
+};
+
+static int pmsgOpen()
+{
+    if (pmsgLoggerWrite.context.fd < 0) {
+        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    }
+
+    return pmsgLoggerWrite.context.fd;
+}
+
+static void pmsgClose()
+{
+    if (pmsgLoggerWrite.context.fd >= 0) {
+        close(pmsgLoggerWrite.context.fd);
+        pmsgLoggerWrite.context.fd = -1;
+    }
+}
+
+static int pmsgAvailable(log_id_t logId)
+{
+    if (logId > LOG_ID_SECURITY) {
+        return -EINVAL;
+    }
+    if (pmsgLoggerWrite.context.fd < 0) {
+        if (access("/dev/pmsg0", W_OK) == 0) {
+            return 0;
+        }
+        return -EBADF;
+    }
+    return 1;
+}
+
+static int pmsgWrite(log_id_t logId, struct timespec *ts,
+                      struct iovec *vec, size_t nr)
+{
+    static const unsigned headerLength = 2;
+    struct iovec newVec[nr + headerLength];
+    android_log_header_t header;
+    android_pmsg_log_header_t pmsgHeader;
+    size_t i, payloadSize;
+    ssize_t ret;
+
+    if (pmsgLoggerWrite.context.fd < 0) {
+        return -EBADF;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsgHeader;
+     *      // what we provide to file
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    pmsgHeader.magic = LOGGER_MAGIC;
+    pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
+    pmsgHeader.uid = __android_log_uid();
+    pmsgHeader.pid = __android_log_pid();
+
+    header.id = logId;
+    header.tid = gettid();
+    header.realtime.tv_sec = ts->tv_sec;
+    header.realtime.tv_nsec = ts->tv_nsec;
+
+    newVec[0].iov_base   = (unsigned char *)&pmsgHeader;
+    newVec[0].iov_len    = sizeof(pmsgHeader);
+    newVec[1].iov_base   = (unsigned char *)&header;
+    newVec[1].iov_len    = sizeof(header);
+
+    for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+        newVec[i].iov_base = vec[i - headerLength].iov_base;
+        payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+        if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
+            break;
+        }
+    }
+    pmsgHeader.len += payloadSize;
+
+    ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
+    if (ret < 0) {
+        ret = errno ? -errno : -ENOTCONN;
+    }
+
+    if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
+        ret -= sizeof(header) - sizeof(pmsgHeader);
+    }
+
+    return ret;
+}