Merge "Fix incorrect handling of snprintf return value."
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index c4ffc85..8ef9948 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -44,6 +44,7 @@
 };
 
 static fdevent listener_fde;
+static fdevent framework_fde;
 static int framework_fd = -1;
 
 static void usb_disconnected(void* unused, atransport* t);
@@ -161,29 +162,30 @@
     return ret;
 }
 
-static void usb_disconnected(void* unused, atransport* t)
-{
+static void usb_disconnected(void* unused, atransport* t) {
     D("USB disconnect");
     usb_transport = NULL;
     needs_retry = false;
 }
 
-static void adb_auth_event(int fd, unsigned events, void *data)
-{
+static void framework_disconnected() {
+    D("Framework disconnect");
+    fdevent_remove(&framework_fde);
+    framework_fd = -1;
+}
+
+static void adb_auth_event(int fd, unsigned events, void*) {
     char response[2];
     int ret;
 
     if (events & FDE_READ) {
         ret = unix_read(fd, response, sizeof(response));
         if (ret <= 0) {
-            D("Framework disconnect");
-            if (usb_transport)
-                fdevent_remove(&usb_transport->auth_fde);
-            framework_fd = -1;
-        }
-        else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
-            if (usb_transport)
+            framework_disconnected();
+        } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
+            if (usb_transport) {
                 adb_auth_verified(usb_transport);
+            }
         }
     }
 }
@@ -221,13 +223,9 @@
         D("Failed to write PK, errno=%d", errno);
         return;
     }
-
-    fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);
-    fdevent_add(&t->auth_fde, FDE_READ);
 }
 
-static void adb_auth_listener(int fd, unsigned events, void *data)
-{
+static void adb_auth_listener(int fd, unsigned events, void* data) {
     sockaddr_storage addr;
     socklen_t alen;
     int s;
@@ -240,7 +238,14 @@
         return;
     }
 
+    if (framework_fd >= 0) {
+        PLOG(WARNING) << "adb received framework auth socket connection again";
+        framework_disconnected();
+    }
+
     framework_fd = s;
+    fdevent_install(&framework_fde, framework_fd, adb_auth_event, nullptr);
+    fdevent_add(&framework_fde, FDE_READ);
 
     if (needs_retry) {
         needs_retry = false;
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 8e76168..37d1146 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1106,8 +1106,9 @@
         }
 
         fprintf(stderr,"- waiting for device -\n");
-        adb_sleep_ms(1000);
-        wait_for_device("wait-for-device", transport_type, serial);
+        if (!wait_for_device("wait-for-device", transport_type, serial)) {
+            return 1;
+        }
     }
 
     int exit_code = read_and_dump(fd, use_shell_protocol);
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/transport.h b/adb/transport.h
index 76d6afa..4c0c008 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -50,7 +50,6 @@
     // it's better to do this piece by piece.
 
     atransport() {
-        auth_fde = {};
         transport_fde = {};
         protocol_version = A_VERSION;
         max_payload = MAX_PAYLOAD;
@@ -87,7 +86,6 @@
 
     void* key = nullptr;
     unsigned char token[TOKEN_SIZE] = {};
-    fdevent auth_fde;
     size_t failed_auth_attempts = 0;
 
     const std::string connection_state_name() const;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 97fc069..1bdea2a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -53,7 +53,6 @@
 
         EXPECT_EQ(key, rhs.key);
         EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
-        EXPECT_EQ(0, memcmp(&auth_fde, &rhs.auth_fde, sizeof(fdevent)));
         EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
 
         EXPECT_EQ(features(), rhs.features());
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/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index b3fdcb4..31d9f0f 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -36,6 +36,7 @@
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <brillo/key_value_store.h>
+#include <brillo/osrelease_reader.h>
 #include <brillo/process.h>
 
 namespace {
@@ -52,6 +53,11 @@
 const char kUploadVarPrefix[] = "upload_var_";
 const char kUploadFilePrefix[] = "upload_file_";
 
+// Product information keys in the /etc/os-release.d folder.
+static const char kBdkVersionKey[] = "bdk_version";
+static const char kProductIDKey[] = "product_id";
+static const char kProductVersionKey[] = "product_version";
+
 // Normally this path is not used.  Unfortunately, there are a few edge cases
 // where we need this.  Any process that runs as kDefaultUserName that crashes
 // is consider a "user crash".  That includes the initial Chrome browser that
@@ -384,14 +390,49 @@
                                         const std::string &payload_path) {
   int64_t payload_size = -1;
   base::GetFileSize(FilePath(payload_path), &payload_size);
+
+  brillo::OsReleaseReader reader;
+  if (!forced_osreleased_directory_.empty()) {
+    reader.LoadTestingOnly(forced_osreleased_directory_);
+  } else {
+    reader.Load();
+  }
+  std::string bdk_version = "undefined";
+  std::string product_id = "undefined";
+  std::string product_version = "undefined";
+
+  if (!reader.GetString(kBdkVersionKey, &bdk_version)) {
+    LOG(ERROR) << "Could not read " << kBdkVersionKey
+               << " from /etc/os-release.d/";
+  }
+
+  if (!reader.GetString(kProductIDKey, &product_id)) {
+    LOG(ERROR) << "Could not read " << kProductIDKey
+               << " from /etc/os-release.d/";
+  }
+
+  if (!reader.GetString(kProductVersionKey, &product_version)) {
+    LOG(ERROR) << "Could not read " << kProductVersionKey
+               << " from /etc/os-release.d/";
+  }
+
   std::string meta_data = StringPrintf("%sexec_name=%s\n"
                                        "payload=%s\n"
                                        "payload_size=%" PRId64 "\n"
+                                       "%s=%s\n"
+                                       "%s=%s\n"
+                                       "%s=%s\n"
                                        "done=1\n",
                                        extra_metadata_.c_str(),
                                        exec_name.c_str(),
                                        payload_path.c_str(),
-                                       payload_size);
+                                       payload_size,
+                                       kBdkVersionKey,
+                                       bdk_version.c_str(),
+                                       kProductIDKey,
+                                       product_id.c_str(),
+                                       kProductVersionKey,
+                                       product_version.c_str());
   // We must use WriteNewFile instead of base::WriteFile as we
   // do not want to write with root access to a symlink that an attacker
   // might have created.
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index 24cbfb3..21b9198 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -84,6 +84,12 @@
     forced_crash_directory_ = forced_directory;
   }
 
+  // For testing, set the root directory to read etc/os-release.d properties
+  // from.
+  void ForceOsReleaseDDirectory(const base::FilePath &forced_directory) {
+    forced_osreleased_directory_ = forced_directory;
+  }
+
   base::FilePath GetCrashDirectoryInfo(mode_t *mode,
                                        uid_t *directory_owner,
                                        gid_t *directory_group);
@@ -158,6 +164,7 @@
   IsFeedbackAllowedFunction is_feedback_allowed_function_;
   std::string extra_metadata_;
   base::FilePath forced_crash_directory_;
+  base::FilePath forced_osreleased_directory_;
   base::FilePath log_config_path_;
 
  private:
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index 11c8c0d..90a209d 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -182,9 +182,26 @@
   const char kMetaFileBasename[] = "generated.meta";
   FilePath meta_file = test_dir_.path().Append(kMetaFileBasename);
   FilePath payload_file = test_dir_.path().Append("payload-file");
+  FilePath osreleased_directory =
+      test_dir_.path().Append("etc").Append("os-release.d");
+  ASSERT_TRUE(base::CreateDirectory(osreleased_directory));
+  collector_.ForceOsReleaseDDirectory(test_dir_.path());
+
   std::string contents;
   const char kPayload[] = "foo";
   ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
+  const char kBdkVersion[] = "1";
+  ASSERT_TRUE(base::WriteFile(osreleased_directory.Append("bdk_version"),
+                              kBdkVersion,
+                              strlen(kBdkVersion)));
+  const char kProductId[] = "baz";
+  ASSERT_TRUE(base::WriteFile(osreleased_directory.Append("product_id"),
+                              kProductId,
+                              strlen(kProductId)));
+  const char kProductVersion[] = "1.2.3.4";
+  ASSERT_TRUE(base::WriteFile(osreleased_directory.Append("product_version"),
+                              kProductVersion,
+                              strlen(kProductVersion)));
   collector_.AddCrashMetaData("foo", "bar");
   collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
   EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
@@ -193,6 +210,9 @@
           "exec_name=kernel\n"
           "payload=%s\n"
           "payload_size=3\n"
+          "bdk_version=1\n"
+          "product_id=baz\n"
+          "product_version=1.2.3.4\n"
           "done=1\n",
           test_dir_.path().Append("payload-file").value().c_str());
   EXPECT_EQ(kExpectedMeta, contents);
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 98d7448..48b64e9 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -37,7 +37,6 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <brillo/osrelease_reader.h>
 #include <brillo/process.h>
 #include <brillo/syslog_logging.h>
 #include <cutils/properties.h>
@@ -59,11 +58,6 @@
 const char *UserCollector::kUserId = "Uid:\t";
 const char *UserCollector::kGroupId = "Gid:\t";
 
-// Product information keys in the /etc/os-release.d folder.
-static const char kBdkVersionKey[] = "bdk_version";
-static const char kProductIDKey[] = "product_id";
-static const char kProductVersionKey[] = "product_version";
-
 
 using base::FilePath;
 using base::StringPrintf;
@@ -505,29 +499,6 @@
   if (GetLogContents(FilePath(log_config_path_), exec, log_path))
     AddCrashMetaData("log", log_path.value());
 
-  brillo::OsReleaseReader reader;
-  reader.Load();
-  std::string value = "undefined";
-  if (!reader.GetString(kBdkVersionKey, &value)) {
-    LOG(ERROR) << "Could not read " << kBdkVersionKey
-               << " from /etc/os-release.d/";
-  }
-  AddCrashMetaData(kBdkVersionKey, value);
-
-  value = "undefined";
-  if (!reader.GetString(kProductIDKey, &value)) {
-    LOG(ERROR) << "Could not read " << kProductIDKey
-               << " from /etc/os-release.d/";
-  }
-  AddCrashMetaData(kProductIDKey, value);
-
-  value = "undefined";
-  if (!reader.GetString(kProductVersionKey, &value)) {
-    LOG(ERROR) << "Could not read " << kProductVersionKey
-               << " from /etc/os-release.d/";
-  }
-  AddCrashMetaData(kProductVersionKey, value);
-
   ErrorType error_type =
       ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
   if (error_type != kErrorNone) {
diff --git a/include/log/log.h b/include/log/log.h
index 6ad6f0a..e606a84 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -589,6 +589,8 @@
 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_string8_len(android_log_context ctx,
+                                  const char *value, size_t maxlen);
 int android_log_write_float32(android_log_context ctx, float value);
 
 /* Submit the composed list context to the specified logger id */
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/init/perfboot.py b/init/perfboot.py
index 91e6c2b..713290b 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -191,9 +191,9 @@
 
 def init_perf(device, output, record_list, tags):
     device.wait()
-    build_type = device.get_prop('ro.build.type')
+    debuggable = device.get_prop('ro.debuggable')
     original_dropbox_max_files = None
-    if build_type != 'user':
+    if debuggable == '1':
         # Workaround for Dropbox issue (http://b/20890386).
         original_dropbox_max_files = disable_dropbox(device)
 
diff --git a/init/util.cpp b/init/util.cpp
index aefdf8f..84b4155 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -102,7 +102,7 @@
                   gid_t gid, const char *socketcon)
 {
     struct sockaddr_un addr;
-    int fd, ret;
+    int fd, ret, savederrno;
     char *filecon;
 
     if (socketcon) {
@@ -140,16 +140,26 @@
     }
 
     ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
-    if (ret) {
-        ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
-        goto out_unlink;
-    }
+    savederrno = errno;
 
     setfscreatecon(NULL);
     freecon(filecon);
 
-    chown(addr.sun_path, uid, gid);
-    chmod(addr.sun_path, perm);
+    if (ret) {
+        ERROR("Failed to bind socket '%s': %s\n", name, strerror(savederrno));
+        goto out_unlink;
+    }
+
+    ret = lchown(addr.sun_path, uid, gid);
+    if (ret) {
+        ERROR("Failed to lchown socket '%s': %s\n", addr.sun_path, strerror(errno));
+        goto out_unlink;
+    }
+    ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
+    if (ret) {
+        ERROR("Failed to fchmodat socket '%s': %s\n", addr.sun_path, strerror(errno));
+        goto out_unlink;
+    }
 
     INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
          addr.sun_path, perm, uid, gid);
diff --git a/liblog/Android.mk b/liblog/Android.mk
index c7b76d8..dd5b518 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,11 +24,10 @@
 # so make sure we do not regret hard-coding it as follows:
 liblog_cflags := -DLIBLOG_LOG_TAG=1005
 
-liblog_host_sources := logd_write.c log_event_write.c fake_log_device.c event.logtags
-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
+liblog_sources := logd_write.c log_event_list.c log_event_write.c
+liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
+liblog_target_sources := $(liblog_sources) event_tag_map.c
+liblog_target_sources += log_time.cpp log_is_loggable.c logprint.c log_read.c
 
 # Shared and static library for host
 # ========================================================
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 50a27c0..2213f21 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -195,9 +195,10 @@
     return 0;
 }
 
-int android_log_write_string8(android_log_context ctx, const char *value) {
+int android_log_write_string8_len(android_log_context ctx,
+                                  const char *value, size_t maxlen) {
     size_t needed;
-    int32_t len;
+    ssize_t len;
     android_log_context_internal *context;
 
     context = (android_log_context_internal *)ctx;
@@ -208,13 +209,13 @@
         return -EIO;
     }
     if (!value) {
-        return -EINVAL;
+        value = "";
     }
-    len = strlen(value);
-    needed = sizeof(uint8_t) + sizeof(len) + len;
+    len = strnlen(value, maxlen);
+    needed = sizeof(uint8_t) + sizeof(int32_t) + len;
     if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
         /* Truncate string for delivery */
-        len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(len);
+        len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
         if (len <= 0) {
             context->overflow = true;
             return -EIO;
@@ -223,9 +224,15 @@
     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);
+    if (len) {
+        memcpy(&context->storage[context->pos + 5], value, len);
+    }
     context->pos += needed;
-    return 0;
+    return len;
+}
+
+int android_log_write_string8(android_log_context ctx, const char *value) {
+    return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
 }
 
 int android_log_write_float32(android_log_context ctx, float value) {
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 0bc42d5..ad42edd 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -15,74 +15,33 @@
  */
 
 #include <errno.h>
-#include <string.h>
 
 #include <log/log.h>
-#include <log/logger.h>
 
-#define MAX_EVENT_PAYLOAD 512
 #define MAX_SUBTAG_LEN 32
 
-static inline void copy4LE(uint8_t *buf, size_t pos, int val)
+int __android_log_error_write(int tag, const char *subTag, int32_t uid,
+                              const char *data, uint32_t dataLen)
 {
-    buf[pos] = val & 0xFF;
-    buf[pos+1] = (val >> 8) & 0xFF;
-    buf[pos+2] = (val >> 16) & 0xFF;
-    buf[pos+3] = (val >> 24) & 0xFF;
-}
+    int ret = -EINVAL;
 
-int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
-                              uint32_t dataLen)
-{
-    uint8_t buf[MAX_EVENT_PAYLOAD];
-    size_t pos = 0;
-    uint32_t subTagLen = 0;
-    uint32_t roomLeftForData = 0;
+    if (subTag && (data || !dataLen)) {
+        android_log_context ctx = create_android_logger(tag);
 
-    if ((subTag == NULL) || ((data == NULL) && (dataLen != 0))) return -EINVAL;
-
-    subTagLen = strlen(subTag);
-
-    // Truncate subtags that are too long.
-    subTagLen = subTagLen > MAX_SUBTAG_LEN ? MAX_SUBTAG_LEN : subTagLen;
-
-    // Truncate dataLen if it is too long.
-    roomLeftForData = MAX_EVENT_PAYLOAD -
-            (1 + // EVENT_TYPE_LIST
-             1 + // Number of elements in list
-             1 + // EVENT_TYPE_STRING
-             sizeof(subTagLen) +
-             subTagLen +
-             1 + // EVENT_TYPE_INT
-             sizeof(uid) +
-             1 + // EVENT_TYPE_STRING
-             sizeof(dataLen));
-    dataLen = dataLen > roomLeftForData ? roomLeftForData : dataLen;
-
-    buf[pos++] = EVENT_TYPE_LIST;
-    buf[pos++] = 3; // Number of elements in the list (subTag, uid, data)
-
-    // Write sub tag.
-    buf[pos++] = EVENT_TYPE_STRING;
-    copy4LE(buf, pos, subTagLen);
-    pos += 4;
-    memcpy(&buf[pos], subTag, subTagLen);
-    pos += subTagLen;
-
-    // Write UID.
-    buf[pos++] = EVENT_TYPE_INT;
-    copy4LE(buf, pos, uid);
-    pos += 4;
-
-    // Write data.
-    buf[pos++] = EVENT_TYPE_STRING;
-    copy4LE(buf, pos, dataLen);
-    pos += 4;
-    if (dataLen != 0)
-    {
-        memcpy(&buf[pos], data, dataLen);
-        pos += dataLen;
+        ret = -ENOMEM;
+        if (ctx) {
+            ret = android_log_write_string8_len(ctx, subTag, MAX_SUBTAG_LEN);
+            if (ret >= 0) {
+                ret = android_log_write_int32(ctx, uid);
+                if (ret >= 0) {
+                    ret = android_log_write_string8_len(ctx, data, dataLen);
+                    if (ret >= 0) {
+                        ret = android_log_write_list(ctx, LOG_ID_EVENTS);
+                    }
+                }
+            }
+            android_log_destroy(&ctx);
+        }
     }
-
-    return __android_log_bwrite(tag, buf, pos);
+    return ret;
 }
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 1317853..50ecd2d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1429,7 +1429,7 @@
     const int TAG = 123456782;
     const char SUBTAG[] = "test-subtag";
     const int UID = -1;
-    const int DATA_LEN = SIZEOF_MAX_PAYLOAD_BUF;
+    const int DATA_LEN = sizeof(max_payload_buf);
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -1500,9 +1500,9 @@
         }
         eventData += dataLen;
 
-        // 4 bytes for the tag, and 512 bytes for the log since the
-        // max_payload_buf should be truncated.
-        ASSERT_EQ(4 + 512, eventData - original);
+        // 4 bytes for the tag, and max_payload_buf should be truncated.
+        ASSERT_LE(4 + 512, eventData - original);      // worst expectations
+        ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
 
         ++count;
     }
@@ -2123,6 +2123,30 @@
     return "[1,[2,[3,[4,[5,[6]]]]]]";
 }
 
+static const char *event_test_android_log_error_write(uint32_t tag, size_t &expected_len) {
+    EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, "dlroW olleH", 11));
+
+    expected_len = sizeof(uint32_t) +
+      sizeof(uint8_t) + sizeof(uint8_t) +
+          sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") - 1 +
+          sizeof(uint8_t) + sizeof(uint32_t) +
+          sizeof(uint8_t) + sizeof(uint32_t) + sizeof("dlroW olleH") - 1;
+
+    return "[Hello World,42,dlroW olleH]";
+}
+
+static const char *event_test_android_log_error_write_null(uint32_t tag, size_t &expected_len) {
+    EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, NULL, 0));
+
+    expected_len = sizeof(uint32_t) +
+      sizeof(uint8_t) + sizeof(uint8_t) +
+          sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") - 1 +
+          sizeof(uint8_t) + sizeof(uint32_t) +
+          sizeof(uint8_t) + sizeof(uint32_t) + sizeof("") - 1;
+
+    return "[Hello World,42,]";
+}
+
 // make sure all user buffers are flushed
 static void print_barrier() {
     std::cout.flush();
@@ -2241,6 +2265,14 @@
     create_android_logger(event_test_7_level_suffix);
 }
 
+TEST(liblog, create_android_logger_android_log_error_write) {
+    create_android_logger(event_test_android_log_error_write);
+}
+
+TEST(liblog, create_android_logger_android_log_error_write_null) {
+    create_android_logger(event_test_android_log_error_write_null);
+}
+
 TEST(liblog, create_android_logger_overflow) {
     android_log_context 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 2dec71f..5644aa6 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -26,6 +26,9 @@
 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);
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index a64b972..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,
@@ -111,7 +109,6 @@
     return it != namespaces_.end() ? it->second : nullptr;
   }
 
- private:
   void PreloadPublicLibraries() {
     // android_init_namespaces() expects all the public libraries
     // to be loaded so that they can be found by soname alone.
@@ -121,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.
@@ -139,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,
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 3663c52..6f88a6d 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -72,7 +72,7 @@
 ifeq ($(TARGET_ARCH),mips)
 LOCAL_CFLAGS += -DALIGN_DOUBLE
 endif
-LOCAL_CFLAGS += -Werror
+LOCAL_CFLAGS += -Werror -fvisibility=protected
 
 LOCAL_STATIC_LIBRARIES := \
 	libcutils \
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index fd45c4a0..6a26d00 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -16,7 +16,10 @@
 
 #include <stdlib.h>
 
+#include <private/android_filesystem_config.h>
+
 #include "FlushCommand.h"
+#include "LogBuffer.h"
 #include "LogBufferElement.h"
 #include "LogCommand.h"
 #include "LogReader.h"
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index fffc9ba..230dd11 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -20,10 +20,13 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/prctl.h>
 #include <sys/uio.h>
 #include <syslog.h>
 
+#include <string>
+
 #include <cutils/properties.h>
 #include <log/logger.h>
 #include <private/android_filesystem_config.h>
@@ -31,7 +34,9 @@
 
 #include "libaudit.h"
 #include "LogAudit.h"
+#include "LogBuffer.h"
 #include "LogKlog.h"
+#include "LogReader.h"
 
 #ifndef AUDITD_ENFORCE_INTEGRITY
 #define AUDITD_ENFORCE_INTEGRITY false
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 455ed58..3a84541 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -18,7 +18,10 @@
 #define _LOGD_LOG_AUDIT_H__
 
 #include <sysutils/SocketListener.h>
-#include "LogReader.h"
+
+#include "LogBuffer.h"
+
+class LogReader;
 
 class LogAudit : public SocketListener {
     LogBuffer *logbuf;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index fde9ad7..eb5194c 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -25,9 +25,11 @@
 #include <log/logger.h>
 #include <private/android_logger.h>
 
+#include "LogBuffer.h"
 #include "LogBufferElement.h"
 #include "LogCommand.h"
 #include "LogReader.h"
+#include "LogUtils.h"
 
 const uint64_t LogBufferElement::FLUSH_ERROR(0);
 atomic_int_fast64_t LogBufferElement::sequence(1);
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 9690489..ac2b128 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -20,13 +20,16 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/prctl.h>
 #include <sys/uio.h>
 #include <syslog.h>
 
 #include <log/logger.h>
 
+#include "LogBuffer.h"
 #include "LogKlog.h"
+#include "LogReader.h"
 
 #define KMSG_PRIORITY(PRI)           \
     '<',                             \
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 3c8cc87..ee73b71 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -19,10 +19,12 @@
 
 #include <sysutils/SocketListener.h>
 #include <log/log_read.h>
-#include "LogReader.h"
 
 char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
 
+class LogBuffer;
+class LogReader;
+
 class LogKlog : public SocketListener {
     LogBuffer *logbuf;
     LogReader *reader;
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 846dd7c..39dd227 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -27,6 +27,7 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include "LogBuffer.h"
 #include "LogListener.h"
 #include "LogUtils.h"
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 667a3f2..2c07984 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -18,11 +18,15 @@
 #include <poll.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 
 #include <cutils/sockets.h>
 
-#include "LogReader.h"
 #include "FlushCommand.h"
+#include "LogBuffer.h"
+#include "LogBufferElement.h"
+#include "LogReader.h"
+#include "LogUtils.h"
 
 LogReader::LogReader(LogBuffer *logbuf) :
         SocketListener(getLogSocket(), true),
@@ -176,6 +180,11 @@
     }
 
     FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
+
+    // Set acceptable upper limit to wait for slow reader processing b/27242723
+    struct timeval t = { LOGD_SNDTIMEO, 0 };
+    setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char *)&t, sizeof(t));
+
     command.runSocketCommand(cli);
     return true;
 }
diff --git a/logd/LogReader.h b/logd/LogReader.h
index 91559a3..98674b8 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -18,8 +18,10 @@
 #define _LOGD_LOG_WRITER_H__
 
 #include <sysutils/SocketListener.h>
-#include "LogBuffer.h"
-#include "LogTimes.h"
+
+#define LOGD_SNDTIMEO 32
+
+class LogBuffer;
 
 class LogReader : public SocketListener {
     LogBuffer &mLogbuf;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 1117088..f5969df 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -27,6 +27,7 @@
 #include <log/log.h>
 
 class LogReader;
+class LogBufferElement;
 
 class LogTimeEntry {
     static pthread_mutex_t timesLock;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index de19790..2014374 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -30,6 +30,8 @@
 #include <log/log.h>
 #include <log/logger.h>
 
+#include "../LogReader.h" // pickup LOGD_SNDTIMEO
+
 /*
  * returns statistics
  */
@@ -253,6 +255,9 @@
         fprintf(stderr, "lid=crash ");
         break;
     case 5:
+        fprintf(stderr, "lid=security ");
+        break;
+    case 6:
         fprintf(stderr, "lid=kernel ");
         break;
     default:
@@ -710,3 +715,56 @@
     EXPECT_TRUE(content_timeout);
     EXPECT_NE(0U, alarm_timeout);
 }
+
+// b/27242723 confirmed fixed
+TEST(logd, SNDTIMEO) {
+    static const unsigned sndtimeo = LOGD_SNDTIMEO; // <sigh> it has to be done!
+    static const unsigned sleep_time = sndtimeo + 3;
+    static const unsigned alarm_time = sleep_time + 5;
+
+    int fd;
+
+    ASSERT_TRUE((fd = socket_local_client("logdr",
+                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                 SOCK_SEQPACKET)) > 0);
+
+    struct sigaction ignore, old_sigaction;
+    memset(&ignore, 0, sizeof(ignore));
+    ignore.sa_handler = caught_signal;
+    sigemptyset(&ignore.sa_mask);
+    sigaction(SIGALRM, &ignore, &old_sigaction);
+    unsigned int old_alarm = alarm(alarm_time);
+
+    static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
+    bool reader_requested = write(fd, ask, sizeof(ask)) == sizeof(ask);
+    EXPECT_TRUE(reader_requested);
+
+    log_msg msg;
+    bool read_one = recv(fd, msg.buf, sizeof(msg), 0) > 0;
+
+    EXPECT_TRUE(read_one);
+    if (read_one) {
+        dump_log_msg("user", &msg, 3, -1);
+    }
+
+    fprintf (stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
+    sleep(sleep_time);
+
+    // flush will block if we did not trigger. if it did, last entry returns 0
+    int recv_ret;
+    do {
+        recv_ret = recv(fd, msg.buf, sizeof(msg), 0);
+    } while (recv_ret > 0);
+    int save_errno = (recv_ret < 0) ? errno : 0;
+
+    EXPECT_NE(0U, alarm(old_alarm));
+    sigaction(SIGALRM, &old_sigaction, NULL);
+
+    EXPECT_EQ(0, recv_ret);
+    if (recv_ret > 0) {
+        dump_log_msg("user", &msg, 3, -1);
+    }
+    EXPECT_EQ(0, save_errno);
+
+    close(fd);
+}
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