Merge "logd: print a message when kicking a client or skipping entries"
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 22cf43b..2886289 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -494,7 +494,7 @@
 
 // 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) {
+static const TagFmt* __getEventTag([[maybe_unused]] 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.
@@ -515,8 +515,9 @@
     } else {
       size = ret;
     }
+#ifdef __ANDROID__
     // Ask event log tag service for an existing entry
-    if (__send_log_msg(buf, size) >= 0) {
+    if (SendLogdControlMessage(buf, size) >= 0) {
       buf[size - 1] = '\0';
       char* ep;
       unsigned long val = strtoul(buf, &ep, 10);  // return size
@@ -529,6 +530,7 @@
         }
       }
     }
+#endif
     free(buf);
   }
   return NULL;
@@ -618,8 +620,9 @@
     } else {
       size = ret;
     }
+#ifdef __ANDROID__
     // Ask event log tag service for an allocation
-    if (__send_log_msg(buf, size) >= 0) {
+    if (SendLogdControlMessage(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
@@ -635,6 +638,7 @@
         }
       }
     }
+#endif
     free(buf);
   }
 
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 428a482..f61bbdc 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -650,10 +650,6 @@
   return fd;
 }
 
-ssize_t __send_log_msg(char*, size_t) {
-  return -ENODEV;
-}
-
 int __android_log_is_loggable(int prio, const char*, int def) {
   int logLevel = def;
   return logLevel >= 0 && prio >= logLevel;
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index ce54db2..bd2256c 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -29,7 +29,6 @@
 int fakeLogClose(int fd);
 ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
 
-ssize_t __send_log_msg(char*, size_t);
 int __android_log_is_loggable(int prio, const char*, int def);
 int __android_log_is_loggable_len(int prio, const char*, size_t, int def);
 int __android_log_is_debuggable();
diff --git a/liblog/log_event_list.cpp b/liblog/log_event_list.cpp
index 7882c96..e9f4a32 100644
--- a/liblog/log_event_list.cpp
+++ b/liblog/log_event_list.cpp
@@ -47,9 +47,6 @@
   uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
 };
 
-// TODO(tomcherry): real C++ structs.
-typedef struct android_log_context_internal android_log_context_internal;
-
 static void init_context(android_log_context_internal* context, uint32_t tag) {
   context->tag = tag;
   context->read_write_flag = kAndroidLoggerWrite;
@@ -110,11 +107,9 @@
   return 0;
 }
 
-int android_log_reset(android_log_context ctx) {
-  android_log_context_internal* context;
+int android_log_reset(android_log_context context) {
   uint32_t tag;
 
-  context = (android_log_context_internal*)ctx;
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -126,10 +121,7 @@
   return 0;
 }
 
-int android_log_parser_reset(android_log_context ctx, const char* msg, size_t len) {
-  android_log_context_internal* context;
-
-  context = (android_log_context_internal*)ctx;
+int android_log_parser_reset(android_log_context context, const char* msg, size_t len) {
   if (!context || (kAndroidLoggerRead != context->read_write_flag)) {
     return -EBADF;
   }
@@ -140,10 +132,7 @@
   return 0;
 }
 
-int android_log_write_list_begin(android_log_context ctx) {
-  android_log_context_internal* context;
-
-  context = (android_log_context_internal*)ctx;
+int android_log_write_list_begin(android_log_context context) {
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -174,8 +163,7 @@
   return 0;
 }
 
-int android_log_write_int32(android_log_context ctx, int32_t value) {
-  android_log_context_internal* context = (android_log_context_internal*)ctx;
+int android_log_write_int32(android_log_context context, int32_t value) {
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -195,8 +183,7 @@
   return 0;
 }
 
-int android_log_write_int64(android_log_context ctx, int64_t value) {
-  android_log_context_internal* context = (android_log_context_internal*)ctx;
+int android_log_write_int64(android_log_context context, int64_t value) {
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -216,8 +203,7 @@
   return 0;
 }
 
-int android_log_write_string8_len(android_log_context ctx, const char* value, size_t maxlen) {
-  android_log_context_internal* context = (android_log_context_internal*)ctx;
+int android_log_write_string8_len(android_log_context context, const char* value, size_t maxlen) {
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -252,8 +238,7 @@
   return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
 }
 
-int android_log_write_float32(android_log_context ctx, float value) {
-  android_log_context_internal* context = (android_log_context_internal*)ctx;
+int android_log_write_float32(android_log_context context, float value) {
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -273,10 +258,7 @@
   return 0;
 }
 
-int android_log_write_list_end(android_log_context ctx) {
-  android_log_context_internal* context;
-
-  context = (android_log_context_internal*)ctx;
+int android_log_write_list_end(android_log_context context) {
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -303,8 +285,7 @@
 /*
  * Logs the list of elements to the event log.
  */
-int android_log_write_list(android_log_context ctx, log_id_t id) {
-  android_log_context_internal* context;
+int android_log_write_list(android_log_context context, log_id_t id) {
   const char* msg;
   ssize_t len;
 
@@ -312,7 +293,6 @@
     return -EINVAL;
   }
 
-  context = (android_log_context_internal*)ctx;
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -337,12 +317,10 @@
                                      : __android_log_security_bwrite(context->tag, msg, len));
 }
 
-int android_log_write_list_buffer(android_log_context ctx, const char** buffer) {
-  android_log_context_internal* context;
+int android_log_write_list_buffer(android_log_context context, const char** buffer) {
   const char* msg;
   ssize_t len;
 
-  context = (android_log_context_internal*)ctx;
   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
     return -EBADF;
   }
@@ -375,12 +353,10 @@
  * this and continues to call this function, the behavior is undefined
  * (although it won't crash).
  */
-static android_log_list_element android_log_read_next_internal(android_log_context ctx, int peek) {
+static android_log_list_element android_log_read_next_internal(android_log_context context,
+                                                               int peek) {
   android_log_list_element elem;
   unsigned pos;
-  android_log_context_internal* context;
-
-  context = (android_log_context_internal*)ctx;
 
   memset(&elem, 0, sizeof(elem));
 
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 619cf8c..96e7a61 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "logd_reader.h"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -35,66 +37,8 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
-#include "log_portability.h"
-#include "logd_reader.h"
 #include "logger.h"
 
-static int logdAvailable(log_id_t LogId);
-static int logdVersion(struct android_log_logger* logger,
-                       struct android_log_transport_context* transp);
-static int logdRead(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp, struct log_msg* log_msg);
-static int logdPoll(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp);
-static void logdClose(struct android_log_logger_list* logger_list,
-                      struct android_log_transport_context* transp);
-static int logdClear(struct android_log_logger* logger,
-                     struct android_log_transport_context* transp);
-static ssize_t logdSetSize(struct android_log_logger* logger,
-                           struct android_log_transport_context* transp, size_t size);
-static ssize_t logdGetSize(struct android_log_logger* logger,
-                           struct android_log_transport_context* transp);
-static ssize_t logdGetReadableSize(struct android_log_logger* logger,
-                                   struct android_log_transport_context* transp);
-static ssize_t logdGetPrune(struct android_log_logger_list* logger,
-                            struct android_log_transport_context* transp, char* buf, size_t len);
-static ssize_t logdSetPrune(struct android_log_logger_list* logger,
-                            struct android_log_transport_context* transp, char* buf, size_t len);
-static ssize_t logdGetStats(struct android_log_logger_list* logger,
-                            struct android_log_transport_context* transp, char* buf, size_t len);
-
-struct android_log_transport_read logdLoggerRead = {
-    .name = "logd",
-    .available = logdAvailable,
-    .version = logdVersion,
-    .close = logdClose,
-    .read = logdRead,
-    .poll = logdPoll,
-    .clear = logdClear,
-    .setSize = logdSetSize,
-    .getSize = logdGetSize,
-    .getReadableSize = logdGetReadableSize,
-    .getPrune = logdGetPrune,
-    .setPrune = logdSetPrune,
-    .getStats = logdGetStats,
-};
-
-static int logdAvailable(log_id_t logId) {
-  if (logId >= LOG_ID_MAX) {
-    return -EINVAL;
-  }
-  if (logId == LOG_ID_SECURITY) {
-    uid_t uid = __android_log_uid();
-    if (uid != AID_SYSTEM) {
-      return -EPERM;
-    }
-  }
-  if (access("/dev/socket/logdw", W_OK) == 0) {
-    return 0;
-  }
-  return -EBADF;
-}
-
 // Connects to /dev/socket/<name> and returns the associated fd or returns -1 on error.
 // O_CLOEXEC is always set.
 static int socket_local_client(const std::string& name, int type) {
@@ -120,8 +64,7 @@
 }
 
 /* worker for sending the command to the logger */
-static ssize_t send_log_msg(struct android_log_logger* logger, const char* msg, char* buf,
-                            size_t buf_size) {
+ssize_t SendLogdControlMessage(char* buf, size_t buf_size) {
   ssize_t ret;
   size_t len;
   char* cp;
@@ -131,10 +74,6 @@
     return sock;
   }
 
-  if (msg) {
-    snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned)-1);
-  }
-
   len = strlen(buf) + 1;
   ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
   if (ret <= 0) {
@@ -185,10 +124,6 @@
   return ret;
 }
 
-ssize_t __send_log_msg(char* buf, size_t buf_size) {
-  return send_log_msg(NULL, NULL, buf, buf_size);
-}
-
 static int check_log_success(char* buf, ssize_t ret) {
   if (ret < 0) {
     return ret;
@@ -202,19 +137,28 @@
   return 0;
 }
 
-static int logdClear(struct android_log_logger* logger,
-                     struct android_log_transport_context* transp __unused) {
+int android_logger_clear(struct logger* logger) {
+  if (!android_logger_is_logd(logger)) {
+    return -EINVAL;
+  }
+  uint32_t log_id = android_logger_get_id(logger);
   char buf[512];
+  snprintf(buf, sizeof(buf), "clear %" PRIu32, log_id);
 
-  return check_log_success(buf, send_log_msg(logger, "clear %d", buf, sizeof(buf)));
+  return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
 }
 
 /* returns the total size of the log's ring buffer */
-static ssize_t logdGetSize(struct android_log_logger* logger,
-                           struct android_log_transport_context* transp __unused) {
-  char buf[512];
+long android_logger_get_log_size(struct logger* logger) {
+  if (!android_logger_is_logd(logger)) {
+    return -EINVAL;
+  }
 
-  ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+  uint32_t log_id = android_logger_get_id(logger);
+  char buf[512];
+  snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
+
+  ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
   if (ret < 0) {
     return ret;
   }
@@ -226,24 +170,32 @@
   return atol(buf);
 }
 
-static ssize_t logdSetSize(struct android_log_logger* logger,
-                           struct android_log_transport_context* transp __unused, size_t size) {
+int android_logger_set_log_size(struct logger* logger, unsigned long size) {
+  if (!android_logger_is_logd(logger)) {
+    return -EINVAL;
+  }
+
+  uint32_t log_id = android_logger_get_id(logger);
   char buf[512];
+  snprintf(buf, sizeof(buf), "setLogSize %" PRIu32 " %lu", log_id, size);
 
-  snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
-
-  return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
+  return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
 }
 
 /*
  * returns the readable size of the log's ring buffer (that is, amount of the
  * log consumed)
  */
-static ssize_t logdGetReadableSize(struct android_log_logger* logger,
-                                   struct android_log_transport_context* transp __unused) {
-  char buf[512];
+long android_logger_get_log_readable_size(struct logger* logger) {
+  if (!android_logger_is_logd(logger)) {
+    return -EINVAL;
+  }
 
-  ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+  uint32_t log_id = android_logger_get_id(logger);
+  char buf[512];
+  snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
+
+  ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
   if (ret < 0) {
     return ret;
   }
@@ -255,22 +207,15 @@
   return atol(buf);
 }
 
-/*
- * returns the logger version
- */
-static int logdVersion(struct android_log_logger* logger __unused,
-                       struct android_log_transport_context* transp __unused) {
-  uid_t uid = __android_log_uid();
-  return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
+int android_logger_get_log_version(struct logger*) {
+  return 4;
 }
 
-/*
- * returns statistics
- */
-static ssize_t logdGetStats(struct android_log_logger_list* logger_list,
-                            struct android_log_transport_context* transp __unused, char* buf,
-                            size_t len) {
-  struct android_log_logger* logger;
+ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
+  if (logger_list->mode & ANDROID_LOG_PSTORE) {
+    return -EINVAL;
+  }
+
   char* cp = buf;
   size_t remaining = len;
   size_t n;
@@ -280,29 +225,35 @@
   remaining -= n;
   cp += n;
 
-  logger_for_each(logger, logger_list) {
-    n = snprintf(cp, remaining, " %d", logger->logId);
-    n = MIN(n, remaining);
-    remaining -= n;
-    cp += n;
+  for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
+    if ((1 << log_id) & logger_list->log_mask) {
+      n = snprintf(cp, remaining, " %zu", log_id);
+      n = MIN(n, remaining);
+      remaining -= n;
+      cp += n;
+    }
   }
 
   if (logger_list->pid) {
     snprintf(cp, remaining, " pid=%u", logger_list->pid);
   }
 
-  return send_log_msg(NULL, NULL, buf, len);
+  return SendLogdControlMessage(buf, len);
+}
+ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
+  if (logger_list->mode & ANDROID_LOG_PSTORE) {
+    return -EINVAL;
+  }
+
+  snprintf(buf, len, "getPruneList");
+  return SendLogdControlMessage(buf, len);
 }
 
-static ssize_t logdGetPrune(struct android_log_logger_list* logger_list __unused,
-                            struct android_log_transport_context* transp __unused, char* buf,
-                            size_t len) {
-  return send_log_msg(NULL, "getPruneList", buf, len);
-}
+int android_logger_set_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
+  if (logger_list->mode & ANDROID_LOG_PSTORE) {
+    return -EINVAL;
+  }
 
-static ssize_t logdSetPrune(struct android_log_logger_list* logger_list __unused,
-                            struct android_log_transport_context* transp __unused, char* buf,
-                            size_t len) {
   const char cmd[] = "setPruneList ";
   const size_t cmdlen = sizeof(cmd) - 1;
 
@@ -313,20 +264,14 @@
   buf[len - 1] = '\0';
   memcpy(buf, cmd, cmdlen);
 
-  return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
+  return check_log_success(buf, SendLogdControlMessage(buf, len));
 }
 
-static int logdOpen(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp) {
-  struct android_log_logger* logger;
+static int logdOpen(struct logger_list* logger_list) {
   char buffer[256], *cp, c;
   int ret, remaining, sock;
 
-  if (!logger_list) {
-    return -EINVAL;
-  }
-
-  sock = atomic_load(&transp->context.sock);
+  sock = atomic_load(&logger_list->fd);
   if (sock > 0) {
     return sock;
   }
@@ -346,12 +291,15 @@
   cp += 5;
   c = '=';
   remaining = sizeof(buffer) - (cp - buffer);
-  logger_for_each(logger, logger_list) {
-    ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
-    ret = MIN(ret, remaining);
-    remaining -= ret;
-    cp += ret;
-    c = ',';
+
+  for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
+    if ((1 << log_id) & logger_list->log_mask) {
+      ret = snprintf(cp, remaining, "%c%zu", c, log_id);
+      ret = MIN(ret, remaining);
+      remaining -= ret;
+      cp += ret;
+      c = ',';
+    }
   }
 
   if (logger_list->tail) {
@@ -396,7 +344,7 @@
     return ret;
   }
 
-  ret = atomic_exchange(&transp->context.sock, sock);
+  ret = atomic_exchange(&logger_list->fd, sock);
   if ((ret > 0) && (ret != sock)) {
     close(ret);
   }
@@ -404,15 +352,12 @@
 }
 
 /* Read from the selected logs */
-static int logdRead(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp, struct log_msg* log_msg) {
-  int ret = logdOpen(logger_list, transp);
+int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {
+  int ret = logdOpen(logger_list);
   if (ret < 0) {
     return ret;
   }
 
-  memset(log_msg, 0, sizeof(*log_msg));
-
   /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
   ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0));
   if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) {
@@ -425,32 +370,9 @@
   return ret;
 }
 
-static int logdPoll(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp) {
-  struct pollfd p;
-
-  int ret = logdOpen(logger_list, transp);
-  if (ret < 0) {
-    return ret;
-  }
-
-  memset(&p, 0, sizeof(p));
-  p.fd = ret;
-  p.events = POLLIN;
-  ret = poll(&p, 1, 20);
-  if ((ret > 0) && !(p.revents & POLLIN)) {
-    ret = 0;
-  }
-  if ((ret == -1) && errno) {
-    return -errno;
-  }
-  return ret;
-}
-
 /* Close all the logs */
-static void logdClose(struct android_log_logger_list* logger_list __unused,
-                      struct android_log_transport_context* transp) {
-  int sock = atomic_exchange(&transp->context.sock, -1);
+void LogdClose(struct logger_list* logger_list) {
+  int sock = atomic_exchange(&logger_list->fd, -1);
   if (sock > 0) {
     close(sock);
   }
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
index 7c53cbb..2d032fa 100644
--- a/liblog/logd_reader.h
+++ b/liblog/logd_reader.h
@@ -18,10 +18,14 @@
 
 #include <unistd.h>
 
+#include "log/log_read.h"
 #include "log_portability.h"
 
 __BEGIN_DECLS
 
-ssize_t __send_log_msg(char* buf, size_t buf_size);
+int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg);
+void LogdClose(struct logger_list* logger_list);
+
+ssize_t SendLogdControlMessage(char* buf, size_t buf_size);
 
 __END_DECLS
diff --git a/liblog/logger.h b/liblog/logger.h
index 02cad22..9d74d29 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -46,84 +46,28 @@
                size_t nr);
 };
 
-struct android_log_logger_list;
-struct android_log_transport_context;
-struct android_log_logger;
-
-struct android_log_transport_read {
-  const char* name; /* human name to describe the transport */
-
-  /* Does not cause resources to be taken */
-  int (*available)(log_id_t logId);
-  int (*version)(struct android_log_logger* logger,
-                 struct android_log_transport_context* transp);
-  /* Release resources taken by the following interfaces */
-  void (*close)(struct android_log_logger_list* logger_list,
-                struct android_log_transport_context* transp);
-  /*
-   * Expect all to instantiate open automagically on any call,
-   * so we do not have an explicit open call.
-   */
-  int (*read)(struct android_log_logger_list* logger_list,
-              struct android_log_transport_context* transp,
-              struct log_msg* log_msg);
-  /* Must only be called if not ANDROID_LOG_NONBLOCK (blocking) */
-  int (*poll)(struct android_log_logger_list* logger_list,
-              struct android_log_transport_context* transp);
-
-  int (*clear)(struct android_log_logger* logger,
-               struct android_log_transport_context* transp);
-  ssize_t (*setSize)(struct android_log_logger* logger,
-                     struct android_log_transport_context* transp, size_t size);
-  ssize_t (*getSize)(struct android_log_logger* logger,
-                     struct android_log_transport_context* transp);
-  ssize_t (*getReadableSize)(struct android_log_logger* logger,
-                             struct android_log_transport_context* transp);
-
-  ssize_t (*getPrune)(struct android_log_logger_list* logger_list,
-                      struct android_log_transport_context* transp, char* buf,
-                      size_t len);
-  ssize_t (*setPrune)(struct android_log_logger_list* logger_list,
-                      struct android_log_transport_context* transp, char* buf,
-                      size_t len);
-  ssize_t (*getStats)(struct android_log_logger_list* logger_list,
-                      struct android_log_transport_context* transp, char* buf,
-                      size_t len);
-};
-
-struct android_log_transport_context {
-  union android_log_context_union context; /* zero init per-transport context */
-
-  struct android_log_transport_read* transport;
-  unsigned logMask;      /* mask of requested log buffers */
-};
-
-struct android_log_logger_list {
-  struct listnode logger;
-  android_log_transport_context transport_context;
-  bool transport_initialized;
+struct logger_list {
+  atomic_int fd;
   int mode;
   unsigned int tail;
   log_time start;
   pid_t pid;
+  uint32_t log_mask;
 };
 
-struct android_log_logger {
-  struct listnode node;
-  struct android_log_logger_list* parent;
+// Format for a 'logger' entry: uintptr_t where only the bottom 32 bits are used.
+// bit 31: Set if this 'logger' is for logd.
+// bit 30: Set if this 'logger' is for pmsg
+// bits 0-2: the decimal value of the log buffer.
+// Other bits are unused.
 
-  log_id_t logId;
-};
+#define LOGGER_LOGD (1U << 31)
+#define LOGGER_PMSG (1U << 30)
+#define LOGGER_LOG_ID_MASK ((1U << 3) - 1)
 
-/* assumes caller has structures read-locked, single threaded, or fenced */
-#define logger_for_each(logp, logger_list)                          \
-  for ((logp) = node_to_item((logger_list)->logger.next,            \
-                             struct android_log_logger, node);      \
-       ((logp) != node_to_item(&(logger_list)->logger,              \
-                               struct android_log_logger, node)) && \
-       ((logp)->parent == (logger_list));                           \
-       (logp) =                                                     \
-           node_to_item((logp)->node.next, struct android_log_logger, node))
+inline bool android_logger_is_logd(struct logger* logger) {
+  return reinterpret_cast<uintptr_t>(logger) & LOGGER_LOGD;
+}
 
 /* OS specific dribs and drabs */
 
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index e8a89eb..c65501c 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -21,6 +21,7 @@
 #include <pthread.h>
 #include <sched.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -30,223 +31,49 @@
 #include <private/android_filesystem_config.h>
 
 #include "log_portability.h"
+#include "logd_reader.h"
 #include "logger.h"
-
-/* android_logger_alloc unimplemented, no use case */
-/* android_logger_free not exported */
-static void android_logger_free(struct logger* logger) {
-  struct android_log_logger* logger_internal = (struct android_log_logger*)logger;
-
-  if (!logger_internal) {
-    return;
-  }
-
-  list_remove(&logger_internal->node);
-
-  free(logger_internal);
-}
-
-/* android_logger_alloc unimplemented, no use case */
+#include "pmsg_reader.h"
 
 /* method for getting the associated sublog id */
 log_id_t android_logger_get_id(struct logger* logger) {
-  return ((struct android_log_logger*)logger)->logId;
+  return static_cast<log_id_t>(reinterpret_cast<uintptr_t>(logger) & LOGGER_LOG_ID_MASK);
 }
 
-static int init_transport_context(struct android_log_logger_list* logger_list) {
+static struct logger_list* android_logger_list_alloc_internal(int mode, unsigned int tail,
+                                                              log_time start, pid_t pid) {
+  auto* logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(struct logger_list)));
   if (!logger_list) {
-    return -EINVAL;
+    return nullptr;
   }
 
-  if (list_empty(&logger_list->logger)) {
-    return -EINVAL;
-  }
-
-  if (logger_list->transport_initialized) {
-    return 0;
-  }
-
-#if (FAKE_LOG_DEVICE == 0)
-  extern struct android_log_transport_read logdLoggerRead;
-  extern struct android_log_transport_read pmsgLoggerRead;
-
-  struct android_log_transport_read* transport;
-  transport = (logger_list->mode & ANDROID_LOG_PSTORE) ? &pmsgLoggerRead : &logdLoggerRead;
-
-  struct android_log_logger* logger;
-  unsigned logMask = 0;
-
-  logger_for_each(logger, logger_list) {
-    log_id_t logId = logger->logId;
-
-    if (logId == LOG_ID_SECURITY && __android_log_uid() != AID_SYSTEM) {
-      continue;
-    }
-    if (transport->read && (!transport->available || transport->available(logId) >= 0)) {
-      logMask |= 1 << logId;
-    }
-  }
-  if (!logMask) {
-    return -ENODEV;
-  }
-
-  logger_list->transport_context.transport = transport;
-  logger_list->transport_context.logMask = logMask;
-#endif
-  return 0;
-}
-
-#define LOGGER_FUNCTION(logger, def, func, args...)                                               \
-  ssize_t ret = -EINVAL;                                                                          \
-  android_log_logger* logger_internal = reinterpret_cast<android_log_logger*>(logger);            \
-                                                                                                  \
-  if (!logger_internal) {                                                                         \
-    return ret;                                                                                   \
-  }                                                                                               \
-  ret = init_transport_context(logger_internal->parent);                                          \
-  if (ret < 0) {                                                                                  \
-    return ret;                                                                                   \
-  }                                                                                               \
-                                                                                                  \
-  ret = (def);                                                                                    \
-  android_log_transport_context* transport_context = &logger_internal->parent->transport_context; \
-  if (transport_context->logMask & (1 << logger_internal->logId) &&                               \
-      transport_context->transport && transport_context->transport->func) {                       \
-    ssize_t retval =                                                                              \
-        (transport_context->transport->func)(logger_internal, transport_context, ##args);         \
-    if (ret >= 0 || ret == (def)) {                                                               \
-      ret = retval;                                                                               \
-    }                                                                                             \
-  }                                                                                               \
-  return ret
-
-int android_logger_clear(struct logger* logger) {
-  LOGGER_FUNCTION(logger, -ENODEV, clear);
-}
-
-/* returns the total size of the log's ring buffer */
-long android_logger_get_log_size(struct logger* logger) {
-  LOGGER_FUNCTION(logger, -ENODEV, getSize);
-}
-
-int android_logger_set_log_size(struct logger* logger, unsigned long size) {
-  LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
-}
-
-/*
- * returns the readable size of the log's ring buffer (that is, amount of the
- * log consumed)
- */
-long android_logger_get_log_readable_size(struct logger* logger) {
-  LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
-}
-
-/*
- * returns the logger version
- */
-int android_logger_get_log_version(struct logger* logger) {
-  LOGGER_FUNCTION(logger, 4, version);
-}
-
-#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...)                                  \
-  android_log_logger_list* logger_list_internal =                                              \
-      reinterpret_cast<android_log_logger_list*>(logger_list);                                 \
-                                                                                               \
-  ssize_t ret = init_transport_context(logger_list_internal);                                  \
-  if (ret < 0) {                                                                               \
-    return ret;                                                                                \
-  }                                                                                            \
-                                                                                               \
-  ret = (def);                                                                                 \
-  android_log_transport_context* transport_context = &logger_list_internal->transport_context; \
-  if (transport_context->transport && transport_context->transport->func) {                    \
-    ssize_t retval =                                                                           \
-        (transport_context->transport->func)(logger_list_internal, transport_context, ##args); \
-    if (ret >= 0 || ret == (def)) {                                                            \
-      ret = retval;                                                                            \
-    }                                                                                          \
-  }                                                                                            \
-  return ret
-
-/*
- * returns statistics
- */
-ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
-  LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
-}
-
-ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
-  LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
-}
-
-int android_logger_set_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
-  LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
-}
-
-struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
-  struct android_log_logger_list* logger_list;
-
-  logger_list = static_cast<android_log_logger_list*>(calloc(1, sizeof(*logger_list)));
-  if (!logger_list) {
-    return NULL;
-  }
-
-  list_init(&logger_list->logger);
   logger_list->mode = mode;
+  logger_list->start = start;
   logger_list->tail = tail;
   logger_list->pid = pid;
 
-  return (struct logger_list*)logger_list;
+  return logger_list;
+}
+
+struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
+  return android_logger_list_alloc_internal(mode, tail, log_time(0, 0), pid);
 }
 
 struct logger_list* android_logger_list_alloc_time(int mode, log_time start, pid_t pid) {
-  struct android_log_logger_list* logger_list;
-
-  logger_list = static_cast<android_log_logger_list*>(calloc(1, sizeof(*logger_list)));
-  if (!logger_list) {
-    return NULL;
-  }
-
-  list_init(&logger_list->logger);
-  logger_list->mode = mode;
-  logger_list->start = start;
-  logger_list->pid = pid;
-
-  return (struct logger_list*)logger_list;
+  return android_logger_list_alloc_internal(mode, 0, start, pid);
 }
 
-/* android_logger_list_register unimplemented, no use case */
-/* android_logger_list_unregister unimplemented, no use case */
-
 /* Open the named log and add it to the logger list */
 struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
-  struct android_log_logger_list* logger_list_internal =
-      (struct android_log_logger_list*)logger_list;
-  struct android_log_logger* logger;
-
-  if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
+  if (!logger_list || (logId >= LOG_ID_MAX)) {
     return nullptr;
   }
 
-  logger_for_each(logger, logger_list_internal) {
-    if (logger->logId == logId) {
-      return reinterpret_cast<struct logger*>(logger);
-    }
-  }
+  logger_list->log_mask |= 1 << logId;
 
-  logger = static_cast<android_log_logger*>(calloc(1, sizeof(*logger)));
-  if (!logger) {
-    return nullptr;
-  }
-
-  logger->logId = logId;
-  list_add_tail(&logger_list_internal->logger, &logger->node);
-  logger->parent = logger_list_internal;
-
-  // Reset known transport to re-evaluate, since we added a new logger.
-  logger_list_internal->transport_initialized = false;
-
-  return (struct logger*)logger;
+  uintptr_t logger = logId;
+  logger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD;
+  return reinterpret_cast<struct logger*>(logger);
 }
 
 /* Open the single named log and make it part of a new logger list */
@@ -266,11 +93,20 @@
   return logger_list;
 }
 
-/* Validate log_msg packet, read function has already been null checked */
-static int android_transport_read(struct android_log_logger_list* logger_list,
-                                  struct android_log_transport_context* transp,
-                                  struct log_msg* log_msg) {
-  int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
+  if (logger_list == nullptr || logger_list->log_mask == 0) {
+    return -EINVAL;
+  }
+
+  int ret = 0;
+
+#if (FAKE_LOG_DEVICE == 0)
+  if (logger_list->mode & ANDROID_LOG_PSTORE) {
+    ret = PmsgRead(logger_list, log_msg);
+  } else {
+    ret = LogdRead(logger_list, log_msg);
+  }
+#endif
 
   if (ret <= 0) {
     return ret;
@@ -295,40 +131,19 @@
   return ret;
 }
 
-/* Read from the selected logs */
-int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
-  struct android_log_logger_list* logger_list_internal =
-      (struct android_log_logger_list*)logger_list;
-
-  int ret = init_transport_context(logger_list_internal);
-  if (ret < 0) {
-    return ret;
-  }
-
-  android_log_transport_context* transport_context = &logger_list_internal->transport_context;
-  return android_transport_read(logger_list_internal, transport_context, log_msg);
-}
-
 /* Close all the logs */
 void android_logger_list_free(struct logger_list* logger_list) {
-  struct android_log_logger_list* logger_list_internal =
-      (struct android_log_logger_list*)logger_list;
-
-  if (logger_list_internal == NULL) {
+  if (logger_list == NULL) {
     return;
   }
 
-  android_log_transport_context* transport_context = &logger_list_internal->transport_context;
-
-  if (transport_context->transport && transport_context->transport->close) {
-    (*transport_context->transport->close)(logger_list_internal, transport_context);
+#if (FAKE_LOG_DEVICE == 0)
+  if (logger_list->mode & ANDROID_LOG_PSTORE) {
+    PmsgClose(logger_list);
+  } else {
+    LogdClose(logger_list);
   }
+#endif
 
-  while (!list_empty(&logger_list_internal->logger)) {
-    struct listnode* node = list_head(&logger_list_internal->logger);
-    struct android_log_logger* logger = node_to_item(node, struct android_log_logger, node);
-    android_logger_free((struct logger*)logger);
-  }
-
-  free(logger_list_internal);
+  free(logger_list);
 }
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index f43ce3a..9390fec 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "pmsg_reader.h"
+
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -26,57 +28,7 @@
 
 #include "logger.h"
 
-static int pmsgAvailable(log_id_t logId);
-static int pmsgVersion(struct android_log_logger* logger,
-                       struct android_log_transport_context* transp);
-static int pmsgRead(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp, struct log_msg* log_msg);
-static void pmsgClose(struct android_log_logger_list* logger_list,
-                      struct android_log_transport_context* transp);
-static int pmsgClear(struct android_log_logger* logger,
-                     struct android_log_transport_context* transp);
-
-struct android_log_transport_read pmsgLoggerRead = {
-    .name = "pmsg",
-    .available = pmsgAvailable,
-    .version = pmsgVersion,
-    .close = pmsgClose,
-    .read = pmsgRead,
-    .poll = NULL,
-    .clear = pmsgClear,
-    .setSize = NULL,
-    .getSize = NULL,
-    .getReadableSize = NULL,
-    .getPrune = NULL,
-    .setPrune = NULL,
-    .getStats = NULL,
-};
-
-static int pmsgAvailable(log_id_t logId) {
-  if (logId > LOG_ID_SECURITY) {
-    return -EINVAL;
-  }
-  if (access("/dev/pmsg0", W_OK) == 0) {
-    return 0;
-  }
-  return -EBADF;
-}
-
-static int pmsgClear(struct android_log_logger* logger __unused,
-                     struct android_log_transport_context* transp __unused) {
-  return unlink("/sys/fs/pstore/pmsg-ramoops-0");
-}
-
-/*
- * returns the logger version
- */
-static int pmsgVersion(struct android_log_logger* logger __unused,
-                       struct android_log_transport_context* transp __unused) {
-  return 4;
-}
-
-static int pmsgRead(struct android_log_logger_list* logger_list,
-                    struct android_log_transport_context* transp, struct log_msg* log_msg) {
+int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg) {
   ssize_t ret;
   off_t current, next;
   struct __attribute__((__packed__)) {
@@ -88,7 +40,7 @@
 
   memset(log_msg, 0, sizeof(*log_msg));
 
-  if (atomic_load(&transp->context.fd) <= 0) {
+  if (atomic_load(&logger_list->fd) <= 0) {
     int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
 
     if (fd < 0) {
@@ -101,7 +53,7 @@
         return -errno;
       }
     }
-    i = atomic_exchange(&transp->context.fd, fd);
+    i = atomic_exchange(&logger_list->fd, fd);
     if ((i > 0) && (i != fd)) {
       close(i);
     }
@@ -112,7 +64,7 @@
     int fd;
 
     if (preread_count < sizeof(buf)) {
-      fd = atomic_load(&transp->context.fd);
+      fd = atomic_load(&logger_list->fd);
       if (fd <= 0) {
         return -EBADF;
       }
@@ -138,7 +90,7 @@
     }
     preread_count = 0;
 
-    if ((transp->logMask & (1 << buf.l.id)) &&
+    if ((logger_list->log_mask & (1 << buf.l.id)) &&
         ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
          ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
           ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
@@ -146,7 +98,7 @@
         (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
       char* msg = log_msg->entry.msg;
       *msg = buf.prio;
-      fd = atomic_load(&transp->context.fd);
+      fd = atomic_load(&logger_list->fd);
       if (fd <= 0) {
         return -EBADF;
       }
@@ -170,7 +122,7 @@
       return ret + sizeof(buf.prio) + log_msg->entry.hdr_size;
     }
 
-    fd = atomic_load(&transp->context.fd);
+    fd = atomic_load(&logger_list->fd);
     if (fd <= 0) {
       return -EBADF;
     }
@@ -178,7 +130,7 @@
     if (current < 0) {
       return -errno;
     }
-    fd = atomic_load(&transp->context.fd);
+    fd = atomic_load(&logger_list->fd);
     if (fd <= 0) {
       return -EBADF;
     }
@@ -192,9 +144,8 @@
   }
 }
 
-static void pmsgClose(struct android_log_logger_list* logger_list __unused,
-                      struct android_log_transport_context* transp) {
-  int fd = atomic_exchange(&transp->context.fd, 0);
+void PmsgClose(struct logger_list* logger_list) {
+  int fd = atomic_exchange(&logger_list->fd, 0);
   if (fd > 0) {
     close(fd);
   }
@@ -211,8 +162,7 @@
 ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
                                      __android_log_pmsg_file_read_fn fn, void* arg) {
   ssize_t ret;
-  struct android_log_logger_list logger_list;
-  struct android_log_transport_context transp;
+  struct logger_list logger_list;
   struct content {
     struct listnode node;
     struct logger_entry entry;
@@ -234,15 +184,14 @@
 
   /* Add just enough clues in logger_list and transp to make API function */
   memset(&logger_list, 0, sizeof(logger_list));
-  memset(&transp, 0, sizeof(transp));
 
   logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
-  transp.logMask = (unsigned)-1;
+  logger_list.log_mask = (unsigned)-1;
   if (logId != LOG_ID_ANY) {
-    transp.logMask = (1 << logId);
+    logger_list.log_mask = (1 << logId);
   }
-  transp.logMask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
-  if (!transp.logMask) {
+  logger_list.log_mask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
+  if (!logger_list.log_mask) {
     return -EINVAL;
   }
 
@@ -268,7 +217,7 @@
 
   /* Read the file content */
   log_msg log_msg;
-  while (pmsgRead(&logger_list, &transp, &log_msg) > 0) {
+  while (PmsgRead(&logger_list, &log_msg) > 0) {
     const char* cp;
     size_t hdr_size = log_msg.entry.hdr_size;
 
@@ -426,7 +375,7 @@
     }
     list_add_head(node, &content->node);
   }
-  pmsgClose(&logger_list, &transp);
+  PmsgClose(&logger_list);
 
   /* Progress through all the collected files */
   list_for_each_safe(node, n, &name_list) {
diff --git a/liblog/pmsg_reader.h b/liblog/pmsg_reader.h
new file mode 100644
index 0000000..53746d8
--- /dev/null
+++ b/liblog/pmsg_reader.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+
+#include "log/log_read.h"
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg);
+void PmsgClose(struct logger_list* logger_list);
+
+__END_DECLS
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 56892a2..39ac7a5 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -913,7 +913,7 @@
 }
 BENCHMARK(BM_lookupEventTagNum);
 
-// Must be functionally identical to liblog internal __send_log_msg.
+// Must be functionally identical to liblog internal SendLogdControlMessage()
 static void send_to_control(char* buf, size_t len) {
   int sock =
       socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM | SOCK_CLOEXEC);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 70ccb80..2d14bf3 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -969,6 +969,16 @@
         }
     }
 
+    if (mode & ANDROID_LOG_PSTORE) {
+        if (clearLog) {
+            unlink("/sys/fs/pstore/pmsg-ramoops-0");
+            return EXIT_SUCCESS;
+        }
+        if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
+            LogcatPanic(HELP_TRUE, "-L is incompatible with -g/-G, -S, and -p/-P");
+        }
+    }
+
     std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
             nullptr, &android_logger_list_free};
     if (tail_time != log_time::EPOCH) {