Merge "adb: fix leak of framework_fd."
diff --git a/adb/Android.mk b/adb/Android.mk
index e0997ea..4777883 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -99,7 +99,6 @@
 LOCAL_SRC_FILES := \
     $(LIBADB_SRC_FILES) \
     adb_auth_client.cpp \
-    fdevent.cpp \
     jdwp_service.cpp \
     usb_linux_client.cpp \
 
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 4721e2f..7f40b96 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -43,24 +43,15 @@
 
 static const char* root_seclabel = nullptr;
 
-static void drop_capabilities_bounding_set_if_needed() {
-#ifdef ALLOW_ADBD_ROOT
+static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
+#if defined(ALLOW_ADBD_ROOT)
     char value[PROPERTY_VALUE_MAX];
     property_get("ro.debuggable", value, "");
     if (strcmp(value, "1") == 0) {
         return;
     }
 #endif
-    for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-        if (i == CAP_SETUID || i == CAP_SETGID) {
-            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
-            continue;
-        }
-
-        if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
-            PLOG(FATAL) << "Could not drop capabilities";
-        }
-    }
+    minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
 }
 
 static bool should_drop_privileges() {
@@ -131,7 +122,7 @@
     // Don't listen on a port (default 5037) if running in secure mode.
     // Don't run as root if running in secure mode.
     if (should_drop_privileges()) {
-        drop_capabilities_bounding_set_if_needed();
+        drop_capabilities_bounding_set_if_needed(jail.get());
 
         minijail_change_gid(jail.get(), AID_SHELL);
         minijail_change_uid(jail.get(), AID_SHELL);
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 3904cc0..78efea8 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -122,12 +122,14 @@
 };
 
 TEST_F(sysdeps_poll, smoke) {
-    adb_pollfd pfd[2];
+    adb_pollfd pfd[2] = {};
     pfd[0].fd = fds[0];
     pfd[0].events = POLLRDNORM;
     pfd[1].fd = fds[1];
     pfd[1].events = POLLWRNORM;
 
+    pfd[0].revents = -1;
+    pfd[1].revents = -1;
     EXPECT_EQ(1, adb_poll(pfd, 2, 0));
     EXPECT_EQ(0, pfd[0].revents);
     EXPECT_EQ(POLLWRNORM, pfd[1].revents);
@@ -135,16 +137,18 @@
     ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
 
     // Wait for the socketpair to be flushed.
+    pfd[0].revents = -1;
     EXPECT_EQ(1, adb_poll(pfd, 1, 100));
     EXPECT_EQ(POLLRDNORM, pfd[0].revents);
-
+    pfd[0].revents = -1;
+    pfd[1].revents = -1;
     EXPECT_EQ(2, adb_poll(pfd, 2, 0));
     EXPECT_EQ(POLLRDNORM, pfd[0].revents);
     EXPECT_EQ(POLLWRNORM, pfd[1].revents);
 }
 
 TEST_F(sysdeps_poll, timeout) {
-    adb_pollfd pfd;
+    adb_pollfd pfd = {};
     pfd.fd = fds[0];
     pfd.events = POLLRDNORM;
 
@@ -158,7 +162,7 @@
 }
 
 TEST_F(sysdeps_poll, invalid_fd) {
-    adb_pollfd pfd[3];
+    adb_pollfd pfd[3] = {};
     pfd[0].fd = fds[0];
     pfd[0].events = POLLRDNORM;
     pfd[1].fd = INT_MAX;
@@ -179,7 +183,7 @@
 }
 
 TEST_F(sysdeps_poll, duplicate_fd) {
-    adb_pollfd pfd[2];
+    adb_pollfd pfd[2] = {};
     pfd[0].fd = fds[0];
     pfd[0].events = POLLRDNORM;
     pfd[1] = pfd[0];
@@ -196,7 +200,7 @@
 }
 
 TEST_F(sysdeps_poll, disconnect) {
-    adb_pollfd pfd;
+    adb_pollfd pfd = {};
     pfd.fd = fds[0];
     pfd.events = POLLIN;
 
diff --git a/bootstat/README.md b/bootstat/README.md
index b3964ce..76ea6c1 100644
--- a/bootstat/README.md
+++ b/bootstat/README.md
@@ -12,6 +12,7 @@
       -p, --print           Dump the boot event records to the console
       -r, --record          Record the timestamp of a named boot event
       --record_boot_reason  Record the reason why the device booted
+      --record_time_since_factory_reset Record the time since the device was reset
 
 ## Relative time ##
 
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 0c49f82..c199190 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -80,7 +80,8 @@
           "  -l, --log             Log all metrics to logstorage\n"
           "  -p, --print           Dump the boot event records to the console\n"
           "  -r, --record          Record the timestamp of a named boot event\n"
-          "  --record_boot_reason  Record the reason why the device booted\n");
+          "  --record_boot_reason  Record the reason why the device booted\n"
+          "  --record_time_since_factory_reset Record the time since the device was reset\n");
 }
 
 // Constructs a readable, printable string from the givencommand line
@@ -192,7 +193,7 @@
 
   int option_index = 0;
   static const char boot_reason_str[] = "record_boot_reason";
-  static const char factory_reset_str[] = "record_factory_reset";
+  static const char factory_reset_str[] = "record_time_since_factory_reset";
   static const struct option long_options[] = {
     { "help",            no_argument,       NULL,   'h' },
     { "log",             no_argument,       NULL,   'l' },
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index 218b9f8..13ef27e 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -13,5 +13,8 @@
     # Record the boot reason.
     exec - root root -- /system/bin/bootstat --record_boot_reason
 
+    # Record time since factory reset.
+    exec - root root -- /system/bin/bootstat --record_time_since_factory_reset
+
     # Log all boot events.
     exec - root root -- /system/bin/bootstat -l
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 294bda9..ac1c58c 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -685,10 +685,9 @@
   act.sa_flags = SA_NOCLDWAIT;
   sigaction(SIGCHLD, &act, 0);
 
-  int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-  if (s < 0)
-    return 1;
-  fcntl(s, F_SETFD, FD_CLOEXEC);
+  int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+                              SOCK_STREAM | SOCK_CLOEXEC);
+  if (s == -1) return 1;
 
   ALOGI("debuggerd: starting\n");
 
@@ -698,14 +697,12 @@
     socklen_t alen = sizeof(ss);
 
     ALOGV("waiting for connection\n");
-    int fd = accept(s, addrp, &alen);
-    if (fd < 0) {
-      ALOGV("accept failed: %s\n", strerror(errno));
+    int fd = accept4(s, addrp, &alen, SOCK_CLOEXEC);
+    if (fd == -1) {
+      ALOGE("accept failed: %s\n", strerror(errno));
       continue;
     }
 
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-
     handle_request(fd);
   }
   return 0;
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 2022ae7..b33dd28 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -323,11 +323,10 @@
                                 " cc=%d", props.batteryCycleCount);
             }
         } else {
-            snprintf(dmesgline, sizeof(dmesgline),
+            len = snprintf(dmesgline, sizeof(dmesgline),
                  "battery none");
         }
 
-        len = strlen(dmesgline);
         snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
                  props.chargerAcOnline ? "a" : "",
                  props.chargerUsbOnline ? "u" : "",
@@ -341,6 +340,17 @@
             props.chargerWirelessOnline;
 }
 
+int BatteryMonitor::getChargeStatus() {
+    int result = BATTERY_STATUS_UNKNOWN;
+    if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
+        char buf[128];
+        if (readFromFile(mHealthdConfig->batteryStatusPath, buf, sizeof(buf)) > 0) {
+            result = getBatteryStatus(buf);
+        }
+    }
+    return result;
+}
+
 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
     status_t ret = BAD_VALUE;
 
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 31c4e09..440f2e4 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -40,6 +40,7 @@
     BatteryMonitor();
     void init(struct healthd_config *hc);
     bool update(void);
+    int getChargeStatus();
     status_t getProperty(int id, struct BatteryProperty *val);
     void dumpState(int fd);
 
diff --git a/include/log/log.h b/include/log/log.h
index 1bd9165..6ad6f0a 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -484,15 +484,19 @@
  */
 
 /*
- * Event log entry types.  These must match up with the declarations in
- * java/android/android/util/EventLog.java.
+ * Event log entry types.
  */
 typedef enum {
-    EVENT_TYPE_INT      = 0,
-    EVENT_TYPE_LONG     = 1,
-    EVENT_TYPE_STRING   = 2,
-    EVENT_TYPE_LIST     = 3,
-    EVENT_TYPE_FLOAT    = 4,
+    /* Special markers for android_log_list_element type */
+    EVENT_TYPE_LIST_STOP = '\n', /* declare end of list  */
+    EVENT_TYPE_UNKNOWN   = '?',  /* protocol error       */
+
+    /* must match with declaration in java/android/android/util/EventLog.java */
+    EVENT_TYPE_INT       = 0,    /* uint32_t */
+    EVENT_TYPE_LONG      = 1,    /* uint64_t */
+    EVENT_TYPE_STRING    = 2,
+    EVENT_TYPE_LIST      = 3,
+    EVENT_TYPE_FLOAT     = 4,
 } AndroidEventLogType;
 #define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
 #define typeof_AndroidEventLogType unsigned char
@@ -522,7 +526,85 @@
 #define LOG_EVENT_STRING(_tag, _value)                                      \
         (void) __android_log_bswrite(_tag, _value);
 #endif
-/* TODO: something for LIST */
+
+typedef enum log_id {
+    LOG_ID_MIN = 0,
+
+#ifndef LINT_RLOG
+    LOG_ID_MAIN = 0,
+#endif
+    LOG_ID_RADIO = 1,
+#ifndef LINT_RLOG
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+    LOG_ID_CRASH = 4,
+    LOG_ID_SECURITY = 5,
+    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+#endif
+
+    LOG_ID_MAX
+} log_id_t;
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+typedef struct android_log_context_internal *android_log_context;
+
+/*
+ * Elements returned when reading a list of events.
+ */
+typedef struct {
+    AndroidEventLogType type;
+    uint16_t complete;
+    uint16_t len;
+    union {
+        int32_t int32;
+        int64_t int64;
+        char *string;
+        float float32;
+    } data;
+} android_log_list_element;
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ *     elements, we will manufacturer a list to embrace it for your API
+ *     convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char *value);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char *msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context *ctx);
 
 /*
  * ===========================================================================
@@ -585,26 +667,6 @@
     (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
 #endif
 
-typedef enum log_id {
-    LOG_ID_MIN = 0,
-
-#ifndef LINT_RLOG
-    LOG_ID_MAIN = 0,
-#endif
-    LOG_ID_RADIO = 1,
-#ifndef LINT_RLOG
-    LOG_ID_EVENTS = 2,
-    LOG_ID_SYSTEM = 3,
-    LOG_ID_CRASH = 4,
-    LOG_ID_SECURITY = 5,
-    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
-#endif
-
-    LOG_ID_MAX
-} log_id_t;
-#define sizeof_log_id_t sizeof(typeof_log_id_t)
-#define typeof_log_id_t unsigned char
-
 /*
  * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
  * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 85d6c19..6232f72 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -88,6 +88,9 @@
 #define AID_WEBSERV       1044  /* webservd process */
 #define AID_DEBUGGERD     1045  /* debuggerd unprivileged user */
 #define AID_MEDIA_CODEC   1046  /* mediacodec process */
+#define AID_CAMERASERVER  1047  /* cameraserver process */
+#define AID_FIREWALL      1048  /* firewalld process */
+#define AID_TRUNKS        1049  /* trunksd process (TPM daemon) */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -194,6 +197,9 @@
     { "webserv",       AID_WEBSERV },
     { "debuggerd",     AID_DEBUGGERD, },
     { "mediacodec",    AID_MEDIA_CODEC, },
+    { "cameraserver",  AID_CAMERASERVER, },
+    { "firewall",      AID_FIREWALL, },
+    { "trunks",        AID_TRUNKS, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 00e211c..14a58ca 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -47,10 +47,7 @@
 
 /* Only call once per process. */
 void qtaguid_resTrack(void) {
-    resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY));
-    if (resTrackFd >=0) {
-        TEMP_FAILURE_RETRY(fcntl(resTrackFd, F_SETFD, FD_CLOEXEC));
-    }
+    resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC));
 }
 
 /*
@@ -63,7 +60,7 @@
 
     ALOGV("write_ctrl(%s)", cmd);
 
-    fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY));
+    fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY | O_CLOEXEC));
     if (fd < 0) {
         return -errno;
     }
@@ -85,7 +82,7 @@
     int param_fd;
     int res;
 
-    param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY));
+    param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY | O_CLOEXEC));
     if (param_fd < 0) {
         return -errno;
     }
diff --git a/liblog/Android.mk b/liblog/Android.mk
index a183db8..c7b76d8 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -28,6 +28,7 @@
 liblog_target_sources := logd_write.c log_event_write.c event_tag_map.c log_time.cpp log_is_loggable.c
 liblog_target_sources += logprint.c
 liblog_target_sources += log_read.c
+liblog_target_sources += log_event_list.c
 
 # Shared and static library for host
 # ========================================================
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 4942c08..aa88bed 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -469,13 +469,13 @@
     if (numLines > MAX_LINES)
         numLines = MAX_LINES;
 
-    numVecs = numLines*3;  // 3 iovecs per line.
+    numVecs = numLines * 3;  // 3 iovecs per line.
     if (numVecs > INLINE_VECS) {
         vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs);
         if (vec == NULL) {
             msg = "LOG: write failed, no memory";
-            numVecs = 3;
-            numLines = 1;
+            numVecs = INLINE_VECS;
+            numLines = numVecs / 3;
             vec = stackVec;
         }
     }
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
new file mode 100644
index 0000000..50a27c0
--- /dev/null
+++ b/liblog/log_event_list.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
+
+typedef struct {
+    uint32_t tag;
+    unsigned pos; /* Read/write position into buffer */
+    unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements   */
+    unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1];  /* pos for list counter */
+    unsigned list_nest_depth;
+    unsigned len; /* Length or raw buffer. */
+    bool overflow;
+    bool list_stop; /* next call decrement list_nest_depth and issue a stop */
+    enum {
+        kAndroidLoggerRead = 1,
+        kAndroidLoggerWrite = 2,
+    } read_write_flag;
+    uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
+} android_log_context_internal;
+
+android_log_context create_android_logger(uint32_t tag) {
+    size_t needed, i;
+    android_log_context_internal *context;
+
+    context = calloc(1, sizeof(android_log_context_internal));
+    if (!context) {
+        return NULL;
+    }
+    context->tag = tag;
+    context->read_write_flag = kAndroidLoggerWrite;
+    needed = sizeof(uint8_t) + sizeof(uint8_t);
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        context->overflow = true;
+    }
+    /* Everything is a list */
+    context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+    context->list[0] = context->pos + 1;
+    context->pos += needed;
+
+    return (android_log_context)context;
+}
+
+android_log_context create_android_log_parser(const char *msg, size_t len) {
+    android_log_context_internal *context;
+    size_t i;
+
+    context = calloc(1, sizeof(android_log_context_internal));
+    if (!context) {
+        return NULL;
+    }
+    len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
+    context->len = len;
+    memcpy(context->storage, msg, len);
+    context->read_write_flag = kAndroidLoggerRead;
+
+    return (android_log_context)context;
+}
+
+int android_log_destroy(android_log_context *ctx) {
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)*ctx;
+    if (!context) {
+        return -EBADF;
+    }
+    memset(context, 0, sizeof(*context));
+    free(context);
+    *ctx = NULL;
+    return 0;
+}
+
+int android_log_write_list_begin(android_log_context ctx) {
+    size_t needed;
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context ||
+            (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+        context->overflow = true;
+        return -EOVERFLOW;
+    }
+    needed = sizeof(uint8_t) + sizeof(uint8_t);
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        context->overflow = true;
+        return -EIO;
+    }
+    context->count[context->list_nest_depth]++;
+    context->list_nest_depth++;
+    if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+        context->overflow = true;
+        return -EOVERFLOW;
+    }
+    if (context->overflow) {
+        return -EIO;
+    }
+    context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+    context->storage[context->pos + 1] = 0;
+    context->list[context->list_nest_depth] = context->pos + 1;
+    context->count[context->list_nest_depth] = 0;
+    context->pos += needed;
+    return 0;
+}
+
+static inline void copy4LE(uint8_t *buf, uint32_t val)
+{
+    buf[0] = val & 0xFF;
+    buf[1] = (val >> 8) & 0xFF;
+    buf[2] = (val >> 16) & 0xFF;
+    buf[3] = (val >> 24) & 0xFF;
+}
+
+int android_log_write_int32(android_log_context ctx, int32_t value) {
+    size_t needed;
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->overflow) {
+        return -EIO;
+    }
+    needed = sizeof(uint8_t) + sizeof(value);
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        context->overflow = true;
+        return -EIO;
+    }
+    context->count[context->list_nest_depth]++;
+    context->storage[context->pos + 0] = EVENT_TYPE_INT;
+    copy4LE(&context->storage[context->pos + 1], value);
+    context->pos += needed;
+    return 0;
+}
+
+static inline void copy8LE(uint8_t *buf, uint64_t val)
+{
+    buf[0] = val & 0xFF;
+    buf[1] = (val >> 8) & 0xFF;
+    buf[2] = (val >> 16) & 0xFF;
+    buf[3] = (val >> 24) & 0xFF;
+    buf[4] = (val >> 32) & 0xFF;
+    buf[5] = (val >> 40) & 0xFF;
+    buf[6] = (val >> 48) & 0xFF;
+    buf[7] = (val >> 56) & 0xFF;
+}
+
+int android_log_write_int64(android_log_context ctx, int64_t value) {
+    size_t needed;
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->overflow) {
+        return -EIO;
+    }
+    needed = sizeof(uint8_t) + sizeof(value);
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        context->overflow = true;
+        return -EIO;
+    }
+    context->count[context->list_nest_depth]++;
+    context->storage[context->pos + 0] = EVENT_TYPE_LONG;
+    copy8LE(&context->storage[context->pos + 1], value);
+    context->pos += needed;
+    return 0;
+}
+
+int android_log_write_string8(android_log_context ctx, const char *value) {
+    size_t needed;
+    int32_t len;
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->overflow) {
+        return -EIO;
+    }
+    if (!value) {
+        return -EINVAL;
+    }
+    len = strlen(value);
+    needed = sizeof(uint8_t) + sizeof(len) + len;
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        /* Truncate string for delivery */
+        len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(len);
+        if (len <= 0) {
+            context->overflow = true;
+            return -EIO;
+        }
+    }
+    context->count[context->list_nest_depth]++;
+    context->storage[context->pos + 0] = EVENT_TYPE_STRING;
+    copy4LE(&context->storage[context->pos + 1], len);
+    memcpy(&context->storage[context->pos + 5], value, len);
+    context->pos += needed;
+    return 0;
+}
+
+int android_log_write_float32(android_log_context ctx, float value) {
+    size_t needed;
+    uint32_t ivalue;
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->overflow) {
+        return -EIO;
+    }
+    needed = sizeof(uint8_t) + sizeof(ivalue);
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        context->overflow = true;
+        return -EIO;
+    }
+    ivalue = *(uint32_t *)&value;
+    context->count[context->list_nest_depth]++;
+    context->storage[context->pos + 0] = EVENT_TYPE_FLOAT;
+    copy4LE(&context->storage[context->pos + 1], ivalue);
+    context->pos += needed;
+    return 0;
+}
+
+int android_log_write_list_end(android_log_context ctx) {
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+        context->overflow = true;
+        context->list_nest_depth--;
+        return -EOVERFLOW;
+    }
+    if (!context->list_nest_depth) {
+        context->overflow = true;
+        return -EOVERFLOW;
+    }
+    if (context->list[context->list_nest_depth] <= 0) {
+        context->list_nest_depth--;
+        context->overflow = true;
+        return -EOVERFLOW;
+    }
+    context->storage[context->list[context->list_nest_depth]] =
+        context->count[context->list_nest_depth];
+    context->list_nest_depth--;
+    return 0;
+}
+
+/*
+ * 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;
+    const char *msg;
+    ssize_t len;
+
+    if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
+        return -EINVAL;
+    }
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth) {
+        return -EIO;
+    }
+    /* NB: if there was overflow, then log is truncated. Nothing reported */
+    context->storage[1] = context->count[0];
+    len = context->len = context->pos;
+    msg = (const char *)context->storage;
+    /* it'snot a list */
+    if (context->count[0] <= 1) {
+        len -= sizeof(uint8_t) + sizeof(uint8_t);
+        if (len < 0) {
+            len = 0;
+        }
+        msg += sizeof(uint8_t) + sizeof(uint8_t);
+    }
+    return (id == LOG_ID_EVENTS) ?
+        __android_log_bwrite(context->tag, msg, len) :
+        __android_log_security_bwrite(context->tag, msg, len);
+}
+
+/*
+ * Extract a 4-byte value from a byte stream.
+ */
+static inline uint32_t get4LE(const uint8_t* src)
+{
+    return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+/*
+ * Extract an 8-byte value from a byte stream.
+ */
+static inline uint64_t get8LE(const uint8_t* src)
+{
+    uint32_t low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+    uint32_t high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+    return ((uint64_t) high << 32) | (uint64_t) low;
+}
+
+/*
+ * Gets the next element. Parsing errors result in an EVENT_TYPE_UNKNOWN type.
+ * If there is nothing to process, the complete field is set to non-zero. If
+ * an EVENT_TYPE_UNKNOWN type is returned once, and the caller does not check
+ * 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) {
+    android_log_list_element elem;
+    unsigned pos;
+    android_log_context_internal *context;
+
+    context = (android_log_context_internal *)ctx;
+
+    memset(&elem, 0, sizeof(elem));
+
+    /* Nothing to parse from this context, so return complete. */
+    if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
+            (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
+            (context->count[context->list_nest_depth] >=
+                (MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
+        elem.type = EVENT_TYPE_UNKNOWN;
+        if (context &&
+                (context->list_stop ||
+                ((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
+                    !context->count[context->list_nest_depth]))) {
+            elem.type = EVENT_TYPE_LIST_STOP;
+        }
+        elem.complete = true;
+        return elem;
+    }
+
+    /*
+     * Use a different variable to update the position in case this
+     * operation is a "peek".
+     */
+    pos = context->pos;
+    if (context->list_stop) {
+        elem.type = EVENT_TYPE_LIST_STOP;
+        elem.complete = !context->count[0] && (!context->list_nest_depth ||
+            ((context->list_nest_depth == 1) && !context->count[1]));
+        if (!peek) {
+            /* Suck in superfluous stop */
+            if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
+                context->pos = pos + 1;
+            }
+            if (context->list_nest_depth) {
+                --context->list_nest_depth;
+                if (context->count[context->list_nest_depth]) {
+                    context->list_stop = false;
+                }
+            } else {
+                context->list_stop = false;
+            }
+        }
+        return elem;
+    }
+    if ((pos + 1) > context->len) {
+        elem.type = EVENT_TYPE_UNKNOWN;
+        elem.complete = true;
+        return elem;
+    }
+
+    elem.type = context->storage[pos++];
+    switch ((int)elem.type) {
+    case EVENT_TYPE_FLOAT:
+        /* Rely on union to translate elem.data.int32 into elem.data.float32 */
+        /* FALLTHRU */
+    case EVENT_TYPE_INT:
+        elem.len = sizeof(int32_t);
+        if ((pos + elem.len) > context->len) {
+            elem.type = EVENT_TYPE_UNKNOWN;
+            return elem;
+        }
+        elem.data.int32 = get4LE(&context->storage[pos]);
+        /* common tangeable object suffix */
+        pos += elem.len;
+        elem.complete = !context->list_nest_depth && !context->count[0];
+        if (!peek) {
+            if (!context->count[context->list_nest_depth] ||
+                    !--(context->count[context->list_nest_depth])) {
+                context->list_stop = true;
+            }
+            context->pos = pos;
+        }
+        return elem;
+
+    case EVENT_TYPE_LONG:
+        elem.len = sizeof(int64_t);
+        if ((pos + elem.len) > context->len) {
+            elem.type = EVENT_TYPE_UNKNOWN;
+            return elem;
+        }
+        elem.data.int64 = get8LE(&context->storage[pos]);
+        /* common tangeable object suffix */
+        pos += elem.len;
+        elem.complete = !context->list_nest_depth && !context->count[0];
+        if (!peek) {
+            if (!context->count[context->list_nest_depth] ||
+                    !--(context->count[context->list_nest_depth])) {
+                context->list_stop = true;
+            }
+            context->pos = pos;
+        }
+        return elem;
+
+    case EVENT_TYPE_STRING:
+        if ((pos + sizeof(int32_t)) > context->len) {
+            elem.type = EVENT_TYPE_UNKNOWN;
+            elem.complete = true;
+            return elem;
+        }
+        elem.len = get4LE(&context->storage[pos]);
+        pos += sizeof(int32_t);
+        if ((pos + elem.len) > context->len) {
+            elem.len = context->len - pos; /* truncate string */
+            elem.complete = true;
+            if (!elem.len) {
+                elem.type = EVENT_TYPE_UNKNOWN;
+                return elem;
+            }
+        }
+        elem.data.string = (char *)&context->storage[pos];
+        /* common tangeable object suffix */
+        pos += elem.len;
+        elem.complete = !context->list_nest_depth && !context->count[0];
+        if (!peek) {
+            if (!context->count[context->list_nest_depth] ||
+                    !--(context->count[context->list_nest_depth])) {
+                context->list_stop = true;
+            }
+            context->pos = pos;
+        }
+        return elem;
+
+    case EVENT_TYPE_LIST:
+        if ((pos + sizeof(uint8_t)) > context->len) {
+            elem.type = EVENT_TYPE_UNKNOWN;
+            elem.complete = true;
+            return elem;
+        }
+        elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
+        if (peek) {
+            return elem;
+        }
+        if (context->count[context->list_nest_depth]) {
+            context->count[context->list_nest_depth]--;
+        }
+        context->list_stop = !context->storage[pos];
+        context->list_nest_depth++;
+        if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
+            context->count[context->list_nest_depth] = context->storage[pos];
+        }
+        context->pos = pos + sizeof(uint8_t);
+        return elem;
+
+    case EVENT_TYPE_LIST_STOP: /* Suprise Newline terminates lists. */
+        if (!peek) {
+            context->pos = pos;
+        }
+        elem.type = EVENT_TYPE_UNKNOWN;
+        elem.complete = !context->list_nest_depth;
+        if (context->list_nest_depth > 0) {
+            elem.type = EVENT_TYPE_LIST_STOP;
+            if (!peek) {
+                context->list_nest_depth--;
+            }
+        }
+        return elem;
+
+    default:
+        elem.type = EVENT_TYPE_UNKNOWN;
+        return elem;
+    }
+}
+
+android_log_list_element android_log_read_next(android_log_context ctx) {
+    return android_log_read_next_internal(ctx, 0);
+}
+
+android_log_list_element android_log_peek_next(android_log_context ctx) {
+    return android_log_read_next_internal(ctx, 1);
+}
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 1aff272..fc63d2c 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -503,10 +503,7 @@
     }
 
     if (logger_list->pid) {
-        n = snprintf(cp, remaining, " pid=%u", logger_list->pid);
-        n = min(n, remaining);
-        remaining -= n;
-        cp += n;
+        snprintf(cp, remaining, " pid=%u", logger_list->pid);
     }
 
     return send_log_msg(NULL, NULL, buf, len);
@@ -657,7 +654,6 @@
         preread_count = 0;
     }
 
-    ret = 0;
     while(1) {
         if (preread_count < sizeof(buf)) {
             ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
@@ -834,7 +830,6 @@
         if (logger_list->pid) {
             ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
             ret = min(ret, remaining);
-            remaining -= ret;
             cp += ret;
         }
 
@@ -867,7 +862,6 @@
         logger_list->sock = sock;
     }
 
-    ret = 0;
     while(1) {
         memset(log_msg, 0, sizeof(*log_msg));
 
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index f8d4c4c..1317853 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 The Android Open Source Project
+ * Copyright (C) 2013-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.
@@ -1741,3 +1741,529 @@
 
     android_logger_list_close(logger_list);
 }
+
+static int is_real_element(int type) {
+    return ((type == EVENT_TYPE_INT) ||
+            (type == EVENT_TYPE_LONG) ||
+            (type == EVENT_TYPE_STRING) ||
+            (type == EVENT_TYPE_FLOAT));
+}
+
+int android_log_buffer_to_string(const char *msg, size_t len,
+                                 char *strOut, size_t strOutLen) {
+    android_log_context context = create_android_log_parser(msg, len);
+    android_log_list_element elem;
+    bool overflow = false;
+    /* Reserve 1 byte for null terminator. */
+    size_t origStrOutLen = strOutLen--;
+
+    if (!context) {
+        return -EBADF;
+    }
+
+    memset(&elem, 0, sizeof(elem));
+
+    size_t outCount;
+
+    do {
+        elem = android_log_read_next(context);
+        switch ((int)elem.type) {
+        case EVENT_TYPE_LIST:
+            if (strOutLen == 0) {
+                overflow = true;
+            } else {
+                *strOut++ = '[';
+                strOutLen--;
+            }
+            break;
+
+        case EVENT_TYPE_LIST_STOP:
+            if (strOutLen == 0) {
+                overflow = true;
+            } else {
+                *strOut++ = ']';
+                strOutLen--;
+            }
+            break;
+
+        case EVENT_TYPE_INT:
+            /*
+             * snprintf also requires room for the null terminator, which
+             * we don't care about  but we have allocated enough room for
+             * that
+             */
+            outCount = snprintf(strOut, strOutLen + 1,
+                                "%" PRId32, elem.data.int32);
+            if (outCount <= strOutLen) {
+                strOut += outCount;
+                strOutLen -= outCount;
+            } else {
+                overflow = true;
+            }
+            break;
+
+        case EVENT_TYPE_LONG:
+            /*
+             * snprintf also requires room for the null terminator, which
+             * we don't care about but we have allocated enough room for
+             * that
+             */
+            outCount = snprintf(strOut, strOutLen + 1,
+                                "%" PRId64, elem.data.int64);
+            if (outCount <= strOutLen) {
+                strOut += outCount;
+                strOutLen -= outCount;
+            } else {
+                overflow = true;
+            }
+            break;
+
+        case EVENT_TYPE_FLOAT:
+            /*
+             * snprintf also requires room for the null terminator, which
+             * we don't care about but we have allocated enough room for
+             * that
+             */
+            outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
+            if (outCount <= strOutLen) {
+                strOut += outCount;
+                strOutLen -= outCount;
+            } else {
+                overflow = true;
+            }
+            break;
+
+        default:
+            elem.complete = true;
+            break;
+
+        case EVENT_TYPE_UNKNOWN:
+#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
+            if (elem.complete) {
+                break;
+            }
+#endif
+            elem.data.string = const_cast<char *>("<unknown>");
+            elem.len = strlen(elem.data.string);
+            /* FALLTHRU */
+        case EVENT_TYPE_STRING:
+            if (elem.len <= strOutLen) {
+                memcpy(strOut, elem.data.string, elem.len);
+                strOut += elem.len;
+                strOutLen -= elem.len;
+            } else if (strOutLen > 0) {
+                /* copy what we can */
+                memcpy(strOut, elem.data.string, strOutLen);
+                strOut += strOutLen;
+                strOutLen = 0;
+                overflow = true;
+            }
+            break;
+        }
+
+        if (elem.complete) {
+            break;
+        }
+        /* Determine whether to put a comma or not. */
+        if (!overflow && (is_real_element(elem.type) ||
+                (elem.type == EVENT_TYPE_LIST_STOP))) {
+            android_log_list_element next = android_log_peek_next(context);
+            if (!next.complete && (is_real_element(next.type) ||
+                    (next.type == EVENT_TYPE_LIST))) {
+                if (strOutLen == 0) {
+                    overflow = true;
+                } else {
+                    *strOut++ = ',';
+                    strOutLen--;
+                }
+            }
+        }
+    } while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
+
+    android_log_destroy(&context);
+
+    if (overflow) {
+        if (strOutLen < origStrOutLen) {
+            /* leave an indicator */
+            *(strOut-1) = '!';
+        } else {
+            /* nothing was written at all */
+            *strOut++ = '!';
+        }
+    }
+    *strOut++ = '\0';
+
+    if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
+        fprintf(stderr, "Binary log entry conversion failed\n");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) +
+                   sizeof(uint8_t) + sizeof(uint32_t);
+
+    return "1076895760";
+}
+
+static const char *event_test_int64(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) +
+                   sizeof(uint8_t) + sizeof(uint64_t);
+
+    return "-9191740941672636400";
+}
+
+static const char *event_test_list_int64(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) +
+                   sizeof(uint8_t) + sizeof(uint8_t) +
+                       sizeof(uint8_t) + sizeof(uint64_t);
+
+    return "[-9191740941672636400]";
+}
+
+static const char *event_test_simple_automagic_list(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    // The convenience API where we allow a simple list to be
+    // created without explicit begin or end calls.
+    EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
+    EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) +
+                   sizeof(uint8_t) + sizeof(uint8_t) +
+                       sizeof(uint8_t) + sizeof(uint32_t) +
+                       sizeof(uint8_t) + sizeof(uint64_t);
+
+    return "[1076895760,-9191740941672636400]";
+}
+
+static const char *event_test_list_empty(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) +
+                   sizeof(uint8_t) + sizeof(uint8_t);
+
+    return "[]";
+}
+
+static const char *event_test_complex_nested_list(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+
+    EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
+    EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
+    EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
+    EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
+    EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
+    EXPECT_LE(0, android_log_write_int32(ctx, 1));
+    EXPECT_LE(0, android_log_write_int32(ctx, 2));
+    EXPECT_LE(0, android_log_write_int32(ctx, 3));
+    EXPECT_LE(0, android_log_write_int32(ctx, 4));
+    EXPECT_LE(0, android_log_write_list_end(ctx));   // ]
+    EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
+    EXPECT_LE(0, android_log_write_list_end(ctx));   // ]
+
+    //
+    // This one checks for the automagic list creation because a list
+    // begin and end was missing for it! This is actually an <oops> corner
+    // case, and not the behavior we morally support. The automagic API is to
+    // allow for a simple case of a series of objects in a single list. e.g.
+    //   int32,int32,int32,string -> [int32,int32,int32,string]
+    //
+    EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
+
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) +
+                   sizeof(uint8_t) + sizeof(uint8_t) +
+                       sizeof(uint8_t) + sizeof(uint8_t) +
+                           sizeof(uint8_t) + sizeof(uint32_t) +
+                           sizeof(uint8_t) + sizeof(uint64_t) +
+                           sizeof(uint8_t) + sizeof(uint32_t) +
+                                             sizeof("Hello World") - 1 +
+                           sizeof(uint8_t) + sizeof(uint8_t) +
+                               4 * (sizeof(uint8_t) + sizeof(uint32_t)) +
+                           sizeof(uint8_t) + sizeof(uint32_t) +
+                       sizeof(uint8_t) + sizeof(uint32_t) +
+                                         sizeof("dlroW olleH") - 1;
+
+    return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW olleH]";
+}
+
+static const char *event_test_7_level_prefix(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 1));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 2));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 3));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 4));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 5));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 6));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 7));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) + 7 *
+      (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
+
+    return "[[[[[[[1],2],3],4],5],6],7]";
+}
+
+static const char *event_test_7_level_suffix(uint32_t tag, size_t &expected_len) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+    if (!ctx) {
+        return NULL;
+    }
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 1));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 2));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 3));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 4));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 5));
+    EXPECT_LE(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_write_int32(ctx, 6));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list_end(ctx));
+    EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    EXPECT_TRUE(NULL == ctx);
+
+    expected_len = sizeof(uint32_t) + 6 *
+      (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
+
+    return "[1,[2,[3,[4,[5,[6]]]]]]";
+}
+
+// make sure all user buffers are flushed
+static void print_barrier() {
+    std::cout.flush();
+    fflush(stdout);
+    std::cerr.flush();
+    fflush(stderr); // everything else is paranoia ...
+}
+
+static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    log_time ts(android_log_clockid());
+
+    size_t expected_len;
+    const char *expected_string = (*fn)(1005, expected_len);
+
+    if (!expected_string) {
+        android_logger_list_close(logger_list);
+        return;
+    }
+
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.sec < (ts.tv_sec - 1))
+         || ((ts.tv_sec + 1) < log_msg.entry.sec)
+         || ((size_t)log_msg.entry.len != expected_len)
+         || (log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        ++count;
+
+        AndroidLogFormat *logformat = android_log_format_new();
+        EXPECT_TRUE(NULL != logformat);
+        AndroidLogEntry entry;
+        char msgBuf[1024];
+        int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+            &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+        EXPECT_EQ(0, processBinaryLogBuffer);
+        if (processBinaryLogBuffer == 0) {
+            print_barrier();
+            int printLogLine = android_log_printLogLine(
+                logformat, fileno(stderr), &entry);
+            print_barrier();
+            EXPECT_EQ(20 + (int)strlen(expected_string), printLogLine);
+        }
+        android_log_format_free(logformat);
+
+        // test buffer reading API
+        snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
+        print_barrier();
+        fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
+        memset(msgBuf, 0, sizeof(msgBuf));
+        int buffer_to_string = android_log_buffer_to_string(
+            eventData + sizeof(uint32_t),
+            log_msg.entry.len - sizeof(uint32_t),
+            msgBuf, sizeof(msgBuf));
+        fprintf(stderr, "%s\n", msgBuf);
+        print_barrier();
+        EXPECT_EQ(0, buffer_to_string);
+        EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
+        EXPECT_EQ(0, strcmp(expected_string, msgBuf));
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, create_android_logger_int32) {
+    create_android_logger(event_test_int32);
+}
+
+TEST(liblog, create_android_logger_int64) {
+    create_android_logger(event_test_int64);
+}
+
+TEST(liblog, create_android_logger_list_int64) {
+    create_android_logger(event_test_list_int64);
+}
+
+TEST(liblog, create_android_logger_simple_automagic_list) {
+    create_android_logger(event_test_simple_automagic_list);
+}
+
+TEST(liblog, create_android_logger_list_empty) {
+    create_android_logger(event_test_list_empty);
+}
+
+TEST(liblog, create_android_logger_complex_nested_list) {
+    create_android_logger(event_test_complex_nested_list);
+}
+
+TEST(liblog, create_android_logger_7_level_prefix) {
+    create_android_logger(event_test_7_level_prefix);
+}
+
+TEST(liblog, create_android_logger_7_level_suffix) {
+    create_android_logger(event_test_7_level_suffix);
+}
+
+TEST(liblog, create_android_logger_overflow) {
+    android_log_context ctx;
+
+    EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
+    if (ctx) {
+        for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
+            EXPECT_LE(0, android_log_write_list_begin(ctx));
+        }
+        EXPECT_GT(0, android_log_write_list_begin(ctx));
+        /* One more for good measure, must be permanently unhappy */
+        EXPECT_GT(0, android_log_write_list_begin(ctx));
+        EXPECT_LE(0, android_log_destroy(&ctx));
+        EXPECT_TRUE(NULL == ctx);
+    }
+
+    ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
+    for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
+        EXPECT_LE(0, android_log_write_list_begin(ctx));
+        EXPECT_LE(0, android_log_write_int32(ctx, i));
+    }
+    EXPECT_GT(0, android_log_write_list_begin(ctx));
+    /* One more for good measure, must be permanently unhappy */
+    EXPECT_GT(0, android_log_write_list_begin(ctx));
+    EXPECT_LE(0, android_log_destroy(&ctx));
+    ASSERT_TRUE(NULL == ctx);
+}
diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk
index 3154914..f403621 100644
--- a/libmincrypt/tools/Android.mk
+++ b/libmincrypt/tools/Android.mk
@@ -14,9 +14,19 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# Determine whether to build dumpkey from system/core/libmincrypt or from
+# bootable/recovery/tools. The dumpkey source is temporarily present in both
+# locations during the process of moving the tool to the recovery repository.
+# TODO(mnissler): Remove the guard after the transition is complete.
+ifndef BUILD_DUMPKEY_FROM_RECOVERY
+BUILD_DUMPKEY_FROM_RECOVERY := false
+endif
+
+ifeq ($(BUILD_DUMPKEY_FROM_RECOVERY),false)
 include $(CLEAR_VARS)
 LOCAL_MODULE := dumpkey
 LOCAL_SRC_FILES := DumpPublicKey.java
 LOCAL_JAR_MANIFEST := DumpPublicKey.mf
 LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
 include $(BUILD_HOST_JAVA_LIBRARY)
+endif
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index da07253..5644aa6 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,14 +19,27 @@
 
 #include "jni.h"
 #include <stdint.h>
+#if defined(__ANDROID__)
+#include <android/dlext.h>
+#endif
 
 namespace android {
 
 __attribute__((visibility("default")))
+void PreloadPublicNativeLibraries();
+
+__attribute__((visibility("default")))
 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
                         jobject class_loader, bool is_shared, jstring library_path,
                         jstring permitted_path);
 
+#if defined(__ANDROID__)
+// Look up linker namespace by class_loader. Returns nullptr if
+// there is no namespace associated with the class_loader.
+__attribute__((visibility("default")))
+android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+#endif
+
 };  // namespace android
 
 #endif  // NATIVE_BRIDGE_H_
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index a7a0713..f8bb5fd 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -57,9 +57,7 @@
 
 class LibraryNamespaces {
  public:
-  LibraryNamespaces() : initialized_(false) {
-    PreloadPublicLibraries();
-  }
+  LibraryNamespaces() : initialized_(false) { }
 
   android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader,
                                    bool is_shared,
@@ -79,10 +77,10 @@
 
     std::lock_guard<std::mutex> guard(mutex_);
 
-    auto it = FindNamespaceByClassLoader(env, class_loader);
+    android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
 
-    if (it != namespaces_.end()) {
-      return it->second;
+    if (ns != nullptr) {
+      return ns;
     }
 
     uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -90,21 +88,27 @@
       namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
     }
 
-    android_namespace_t* ns =
-            android_create_namespace("classloader-namespace",
-                                     nullptr,
-                                     library_path.c_str(),
-                                     namespace_type,
-                                     java_permitted_path != nullptr ?
-                                        permitted_path.c_str() :
-                                        nullptr);
+    ns = android_create_namespace("classloader-namespace",
+                                  nullptr,
+                                  library_path.c_str(),
+                                  namespace_type,
+                                  java_permitted_path != nullptr ?
+                                      permitted_path.c_str() :
+                                      nullptr);
 
     namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
 
     return ns;
   }
 
- private:
+  android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+    auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
+                [&](const std::pair<jweak, android_namespace_t*>& value) {
+                  return env->IsSameObject(value.first, class_loader);
+                });
+    return it != namespaces_.end() ? it->second : nullptr;
+  }
+
   void PreloadPublicLibraries() {
     // android_init_namespaces() expects all the public libraries
     // to be loaded so that they can be found by soname alone.
@@ -114,6 +118,7 @@
     }
   }
 
+ private:
   bool InitPublicNamespace(const char* library_path) {
     // Some apps call dlopen from generated code unknown to linker in which
     // case linker uses anonymous namespace. See b/25844435 for details.
@@ -122,14 +127,6 @@
     return initialized_;
   }
 
-  std::vector<std::pair<jweak, android_namespace_t*>>::const_iterator
-  FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
-    return std::find_if(namespaces_.begin(), namespaces_.end(),
-            [&](const std::pair<jweak, android_namespace_t*>& value) {
-              return env->IsSameObject(value.first, class_loader);
-            });
-  }
-
   bool initialized_;
   std::mutex mutex_;
   std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
@@ -140,6 +137,12 @@
 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
 #endif
 
+void PreloadPublicNativeLibraries() {
+#if defined(__ANDROID__)
+  g_namespaces->PreloadPublicLibraries();
+#endif
+}
+
 
 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
                         jobject class_loader, bool is_shared, jstring java_library_path,
@@ -169,4 +172,10 @@
 #endif
 }
 
+#if defined(__ANDROID__)
+android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+}
+#endif
+
 }; //  android namespace
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 168899c..4d602a6 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -206,7 +206,7 @@
 
             do {
                 alen = sizeof(ss);
-                c = accept(mSock, addrp, &alen);
+                c = accept4(mSock, addrp, &alen, SOCK_CLOEXEC);
                 SLOGV("%s got %d from accept", mSocketName, c);
             } while (c < 0 && errno == EINTR);
             if (c < 0) {
@@ -214,7 +214,6 @@
                 sleep(1);
                 continue;
             }
-            fcntl(c, F_SETFD, FD_CLOEXEC);
             pthread_mutex_lock(&mClientsLock);
             mClients->push_back(new SocketClient(c, true, mUseCmdNum));
             pthread_mutex_unlock(&mClientsLock);
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 29bb1cf..4e702a1 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -11,4 +11,4 @@
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 8ed5e9e..692af99 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -11,4 +11,4 @@
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
+    writepid /dev/cpuset/foreground/tasks