Merge "healthd: Correct the scaling factor for maxVoltage and maxCurrent." into nyc-dev
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 37d1146..ff4eb22 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -157,7 +157,7 @@
         "                                 (-r: replace existing application)\n"
         "                                 (-t: allow test packages)\n"
         "                                 (-s: install application on sdcard)\n"
-        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-d: allow version code downgrade (debuggable packages only))\n"
         "                                 (-g: grant all runtime permissions)\n"
         "  adb install-multiple [-lrtsdpg] <file...>\n"
         "                               - push this package file to the device and install it\n"
@@ -165,7 +165,7 @@
         "                                 (-r: replace existing application)\n"
         "                                 (-t: allow test packages)\n"
         "                                 (-s: install application on sdcard)\n"
-        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-d: allow version code downgrade (debuggable packages only))\n"
         "                                 (-p: partial application install)\n"
         "                                 (-g: grant all runtime permissions)\n"
         "  adb uninstall [-k] <package> - remove this app package from the device\n"
diff --git a/base/include/base/unique_fd.h b/base/include/base/unique_fd.h
new file mode 100644
index 0000000..4117775
--- /dev/null
+++ b/base/include/base/unique_fd.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_BASE_UNIQUE_FD_H
+#define ANDROID_BASE_UNIQUE_FD_H
+
+#include <unistd.h>
+
+#include <base/macros.h>
+
+/* Container for a file descriptor that automatically closes the descriptor as
+ * it goes out of scope.
+ *
+ *      unique_fd ufd(open("/some/path", "r"));
+ *
+ *      if (ufd.get() < 0) // invalid descriptor
+ *          return error;
+ *
+ *      // Do something useful
+ *
+ *      return 0; // descriptor is closed here
+ */
+namespace android {
+namespace base {
+
+class unique_fd final {
+ public:
+  unique_fd() : value_(-1) {}
+
+  explicit unique_fd(int value) : value_(value) {}
+  ~unique_fd() { clear(); }
+
+  unique_fd(unique_fd&& other) : value_(other.release()) {}
+  unique_fd& operator = (unique_fd&& s) {
+    reset(s.release());
+    return *this;
+  }
+
+  void reset(int new_value) {
+    if (value_ >= 0)
+      close(value_);
+    value_ = new_value;
+  }
+
+  void clear() {
+    reset(-1);
+  }
+
+  int get() const { return value_; }
+
+  int release() {
+    int ret = value_;
+    value_ = -1;
+    return ret;
+  }
+
+ private:
+  int value_;
+
+  DISALLOW_COPY_AND_ASSIGN(unique_fd);
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif // ANDROID_BASE_UNIQUE_FD_H
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/system/graphics.h b/include/system/graphics.h
index e255614..880cb9f 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -927,9 +927,9 @@
      * The values are encoded using the full range ([0,255] for 8-bit) for all
      * components.
      */
-    HAL_DATASPACE_SRGB_LINEAR_LEGACY = 0x200,
+    HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
 
-    HAL_DATASPACE_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
+    HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
             HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
 
 
@@ -946,9 +946,9 @@
      *
      * Use full range and BT.709 standard.
      */
-    HAL_DATASPACE_SRGB_LEGACY = 0x201,
+    HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
 
-    HAL_DATASPACE_SRGB = HAL_DATASPACE_STANDARD_BT709 |
+    HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
             HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
 
 
@@ -970,9 +970,9 @@
      *
      * Use full range, BT.601 transfer and BT.601_625 standard.
      */
-    HAL_DATASPACE_JFIF_LEGACY = 0x101,
+    HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
 
-    HAL_DATASPACE_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
+    HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
             HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
 
     /*
@@ -982,9 +982,9 @@
      *
      * Use limited range, BT.601 transfer and BT.601_625 standard.
      */
-    HAL_DATASPACE_BT601_625_LEGACY = 0x102,
+    HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
 
-    HAL_DATASPACE_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
+    HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
             HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
 
 
@@ -995,9 +995,9 @@
      *
      * Use limited range, BT.601 transfer and BT.601_525 standard.
      */
-    HAL_DATASPACE_BT601_525_LEGACY = 0x103,
+    HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
 
-    HAL_DATASPACE_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
+    HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
             HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
 
     /*
@@ -1007,9 +1007,9 @@
      *
      * Use limited range, BT.709 transfer and BT.709 standard.
      */
-    HAL_DATASPACE_BT709_LEGACY = 0x104,
+    HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
 
-    HAL_DATASPACE_BT709 = HAL_DATASPACE_STANDARD_BT709 |
+    HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
             HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
 
     /*
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 54d1122..1a26695 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -138,9 +138,9 @@
         ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
 
 #ifdef USE_SCHEDBOOST
-        filename = "/sys/fs/cgroup/stune/foreground/tasks";
+        filename = "/dev/stune/foreground/tasks";
         fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        filename = "/sys/fs/cgroup/stune/tasks";
+        filename = "/dev/stune/tasks";
         bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
 #endif
     }
@@ -266,8 +266,8 @@
     policy = _policy(policy);
     pthread_once(&the_once, __initialize);
 
-    int fd;
-    int boost_fd;
+    int fd = -1;
+    int boost_fd = -1;
     switch (policy) {
     case SP_BACKGROUND:
         fd = bg_cpuset_fd;
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
index 4da5ed6..52cf5f4 100644
--- a/libcutils/tests/Android.mk
+++ b/libcutils/tests/Android.mk
@@ -23,8 +23,9 @@
 test_target_only_src_files := \
     MemsetTest.cpp \
     PropertiesTest.cpp \
+    trace-dev_test.cpp \
 
-test_libraries := libcutils liblog
+test_libraries := libcutils liblog libbase
 
 
 #
diff --git a/libcutils/tests/trace-dev_test.cpp b/libcutils/tests/trace-dev_test.cpp
new file mode 100644
index 0000000..edf981b
--- /dev/null
+++ b/libcutils/tests/trace-dev_test.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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 <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "../trace-dev.c"
+
+class TraceDevTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    lseek(tmp_file_.fd, 0, SEEK_SET);
+    atrace_marker_fd = tmp_file_.fd;
+  }
+
+  void TearDown() override {
+    atrace_marker_fd = -1;
+  }
+
+  TemporaryFile tmp_file_;
+
+  static std::string MakeName(size_t length) {
+    std::string name;
+    for (size_t i = 0; i < length; i++) {
+      name += '0' + (i % 10);
+    }
+    return name;
+  }
+};
+
+TEST_F(TraceDevTest, atrace_begin_body_normal) {
+  atrace_begin_body("fake_name");
+
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  std::string expected = android::base::StringPrintf("B|%d|fake_name", getpid());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_begin_body_exact) {
+  std::string expected = android::base::StringPrintf("B|%d|", getpid());
+  std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1);
+  atrace_begin_body(name.c_str());
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  expected += name;
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  // Add a single character and verify we get the exact same value as before.
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  name += '*';
+  atrace_begin_body(name.c_str());
+  EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_begin_body_truncated) {
+  std::string expected = android::base::StringPrintf("B|%d|", getpid());
+  std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+  atrace_begin_body(name.c_str());
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1;
+  expected += android::base::StringPrintf("%.*s", expected_len, name.c_str());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_async_begin_body_normal) {
+  atrace_async_begin_body("fake_name", 12345);
+
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  std::string expected = android::base::StringPrintf("S|%d|fake_name|12345", getpid());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_async_begin_body_exact) {
+  std::string expected = android::base::StringPrintf("S|%d|", getpid());
+  std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 7);
+  atrace_async_begin_body(name.c_str(), 12345);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  expected += name + "|12345";
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  // Add a single character and verify we get the exact same value as before.
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  name += '*';
+  atrace_async_begin_body(name.c_str(), 12345);
+  EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_async_begin_body_truncated) {
+  std::string expected = android::base::StringPrintf("S|%d|", getpid());
+  std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+  atrace_async_begin_body(name.c_str(), 12345);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 7;
+  expected += android::base::StringPrintf("%.*s|12345", expected_len, name.c_str());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_async_end_body_normal) {
+  atrace_async_end_body("fake_name", 12345);
+
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  std::string expected = android::base::StringPrintf("F|%d|fake_name|12345", getpid());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_async_end_body_exact) {
+  std::string expected = android::base::StringPrintf("F|%d|", getpid());
+  std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 7);
+  atrace_async_end_body(name.c_str(), 12345);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  expected += name + "|12345";
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  // Add a single character and verify we get the exact same value as before.
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  name += '*';
+  atrace_async_end_body(name.c_str(), 12345);
+  EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_async_end_body_truncated) {
+  std::string expected = android::base::StringPrintf("F|%d|", getpid());
+  std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+  atrace_async_end_body(name.c_str(), 12345);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 7;
+  expected += android::base::StringPrintf("%.*s|12345", expected_len, name.c_str());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_int_body_normal) {
+  atrace_int_body("fake_name", 12345);
+
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  std::string expected = android::base::StringPrintf("C|%d|fake_name|12345", getpid());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_int_body_exact) {
+  std::string expected = android::base::StringPrintf("C|%d|", getpid());
+  std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 7);
+  atrace_int_body(name.c_str(), 12345);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  expected += name + "|12345";
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  // Add a single character and verify we get the exact same value as before.
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  name += '*';
+  atrace_int_body(name.c_str(), 12345);
+  EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_int_body_truncated) {
+  std::string expected = android::base::StringPrintf("C|%d|", getpid());
+  std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+  atrace_int_body(name.c_str(), 12345);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 7;
+  expected += android::base::StringPrintf("%.*s|12345", expected_len, name.c_str());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_int64_body_normal) {
+  atrace_int64_body("fake_name", 17179869183L);
+
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  std::string expected = android::base::StringPrintf("C|%d|fake_name|17179869183", getpid());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_int64_body_exact) {
+  std::string expected = android::base::StringPrintf("C|%d|", getpid());
+  std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 13);
+  atrace_int64_body(name.c_str(), 17179869183L);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  expected += name + "|17179869183";
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  // Add a single character and verify we get the exact same value as before.
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  name += '*';
+  atrace_int64_body(name.c_str(), 17179869183L);
+  EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_int64_body_truncated) {
+  std::string expected = android::base::StringPrintf("C|%d|", getpid());
+  std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+  atrace_int64_body(name.c_str(), 17179869183L);
+
+  ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+  ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+  int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 13;
+  expected += android::base::StringPrintf("%.*s|17179869183", expected_len, name.c_str());
+  ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index f025256..5df1c5a 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -194,49 +194,47 @@
 void atrace_begin_body(const char* name)
 {
     char buf[ATRACE_MESSAGE_LENGTH];
-    size_t len;
 
-    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name);
+    int len = snprintf(buf, sizeof(buf), "B|%d|%s", getpid(), name);
+    if (len >= (int) sizeof(buf)) {
+        ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name);
+        len = sizeof(buf) - 1;
+    }
     write(atrace_marker_fd, buf, len);
 }
 
+#define WRITE_MSG(format_begin, format_end, pid, name, value) { \
+    char buf[ATRACE_MESSAGE_LENGTH]; \
+    int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
+        name, value); \
+    if (len >= (int) sizeof(buf)) { \
+        /* Given the sizeof(buf), and all of the current format buffers, \
+         * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
+        int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
+        /* Truncate the name to make the message fit. */ \
+        ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
+        len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
+            name_len, name, value); \
+    } \
+    write(atrace_marker_fd, buf, len); \
+}
 
 void atrace_async_begin_body(const char* name, int32_t cookie)
 {
-    char buf[ATRACE_MESSAGE_LENGTH];
-    size_t len;
-
-    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
-            getpid(), name, cookie);
-    write(atrace_marker_fd, buf, len);
+    WRITE_MSG("S|%d|", "|%" PRId32, getpid(), name, cookie);
 }
 
 void atrace_async_end_body(const char* name, int32_t cookie)
 {
-    char buf[ATRACE_MESSAGE_LENGTH];
-    size_t len;
-
-    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
-            getpid(), name, cookie);
-    write(atrace_marker_fd, buf, len);
+    WRITE_MSG("F|%d|", "|%" PRId32, getpid(), name, cookie);
 }
 
 void atrace_int_body(const char* name, int32_t value)
 {
-    char buf[ATRACE_MESSAGE_LENGTH];
-    size_t len;
-
-    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
-            getpid(), name, value);
-    write(atrace_marker_fd, buf, len);
+    WRITE_MSG("C|%d|", "|%" PRId32, getpid(), name, value);
 }
 
 void atrace_int64_body(const char* name, int64_t value)
 {
-    char buf[ATRACE_MESSAGE_LENGTH];
-    size_t len;
-
-    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
-            getpid(), name, value);
-    write(atrace_marker_fd, buf, len);
+    WRITE_MSG("C|%d|", "|%" PRId64, getpid(), name, value);
 }
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 65d1456..3da4815 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1368,7 +1368,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();
@@ -1439,9 +1439,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;
     }
@@ -2054,6 +2054,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();
@@ -2172,6 +2196,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/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 5644aa6..b16c0e6 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -29,9 +29,19 @@
 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);
+jstring CreateClassLoaderNamespace(JNIEnv* env,
+                                   int32_t target_sdk_version,
+                                   jobject class_loader,
+                                   bool is_shared,
+                                   jstring library_path,
+                                   jstring permitted_path);
+
+__attribute__((visibility("default")))
+void* OpenNativeLibrary(JNIEnv* env,
+                        int32_t target_sdk_version,
+                        const char* path,
+                        jobject class_loader,
+                        jstring library_path);
 
 #if defined(__ANDROID__)
 // Look up linker namespace by class_loader. Returns nullptr if
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index b763631..837924b 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -21,6 +21,7 @@
 #ifdef __ANDROID__
 #include <android/dlext.h>
 #include "cutils/properties.h"
+#include "log/log.h"
 #endif
 
 #include <algorithm>
@@ -61,11 +62,12 @@
  public:
   LibraryNamespaces() : initialized_(false) { }
 
-  android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader,
-                                   bool is_shared,
-                                   jstring java_library_path,
-                                   jstring java_permitted_path,
-                                   int32_t target_sdk_version) {
+  android_namespace_t* Create(JNIEnv* env,
+                              jobject class_loader,
+                              bool is_shared,
+                              jstring java_library_path,
+                              jstring java_permitted_path,
+                              int32_t target_sdk_version) {
     ScopedUtfChars library_path(env, java_library_path);
 
     std::string permitted_path;
@@ -82,9 +84,7 @@
 
     android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
 
-    if (ns != nullptr) {
-      return ns;
-    }
+    LOG_FATAL_IF(ns != nullptr, "There is already a namespace associated with this classloader");
 
     uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
     if (is_shared) {
@@ -99,7 +99,9 @@
                                       permitted_path.c_str() :
                                       nullptr);
 
-    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+    if (ns != nullptr) {
+      namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+    }
 
     return ns;
   }
@@ -147,6 +149,10 @@
 };
 
 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
+
+static bool namespaces_enabled(uint32_t target_sdk_version) {
+  return target_sdk_version > 0;
+}
 #endif
 
 void PreloadPublicNativeLibraries() {
@@ -156,20 +162,52 @@
 }
 
 
-void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
-                        jobject class_loader, bool is_shared, jstring java_library_path,
-                        jstring java_permitted_path) {
+jstring CreateClassLoaderNamespace(JNIEnv* env,
+                                   int32_t target_sdk_version,
+                                   jobject class_loader,
+                                   bool is_shared,
+                                   jstring library_path,
+                                   jstring permitted_path) {
 #if defined(__ANDROID__)
-  if (target_sdk_version == 0 || class_loader == nullptr) {
+  if (!namespaces_enabled(target_sdk_version)) {
+    return nullptr;
+  }
+
+  android_namespace_t* ns = g_namespaces->Create(env,
+                                                 class_loader,
+                                                 is_shared,
+                                                 library_path,
+                                                 permitted_path,
+                                                 target_sdk_version);
+  if (ns == nullptr) {
+    return env->NewStringUTF(dlerror());
+  }
+#else
+  UNUSED(env, target_sdk_version, class_loader, is_shared,
+         library_path, permitted_path);
+#endif
+  return nullptr;
+}
+
+void* OpenNativeLibrary(JNIEnv* env,
+                        int32_t target_sdk_version,
+                        const char* path,
+                        jobject class_loader,
+                        jstring library_path) {
+#if defined(__ANDROID__)
+  if (!namespaces_enabled(target_sdk_version) || class_loader == nullptr) {
     return dlopen(path, RTLD_NOW);
   }
 
-  android_namespace_t* ns =
-      g_namespaces->GetOrCreate(env, class_loader, is_shared,
-                                java_library_path, java_permitted_path, target_sdk_version);
+  android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
 
   if (ns == nullptr) {
-    return nullptr;
+    // This is the case where the classloader was not created by ApplicationLoaders
+    // In this case we create an isolated not-shared namespace for it.
+    ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr, target_sdk_version);
+    if (ns == nullptr) {
+      return nullptr;
+    }
   }
 
   android_dlextinfo extinfo;
@@ -178,8 +216,7 @@
 
   return android_dlopen_ext(path, RTLD_NOW, &extinfo);
 #else
-  UNUSED(env, target_sdk_version, class_loader, is_shared,
-         java_library_path, java_permitted_path);
+  UNUSED(env, target_sdk_version, class_loader, library_path);
   return dlopen(path, RTLD_NOW);
 #endif
 }
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 8c4fd15..3584b6a 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 fd45c4a..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.rc b/rootdir/init.rc
index 3c88d31..3428417 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -44,15 +44,15 @@
     mkdir /acct/uid
 
     # Create energy-aware scheduler tuning nodes
-    mkdir /sys/fs/cgroup/stune
-    mount cgroup none /sys/fs/cgroup/stune schedtune
-    mkdir /sys/fs/cgroup/stune/foreground
-    chown system system /sys/fs/cgroup/stune
-    chown system system /sys/fs/cgroup/stune/foreground
-    chown system system /sys/fs/cgroup/stune/tasks
-    chown system system /sys/fs/cgroup/stune/foreground/tasks
-    chmod 0664 /sys/fs/cgroup/stune/tasks
-    chmod 0664 /sys/fs/cgroup/stune/foreground/tasks
+    mkdir /dev/stune
+    mount cgroup none /dev/stune schedtune
+    mkdir /dev/stune/foreground
+    chown system system /dev/stune
+    chown system system /dev/stune/foreground
+    chown system system /dev/stune/tasks
+    chown system system /dev/stune/foreground/tasks
+    chmod 0664 /dev/stune/tasks
+    chmod 0664 /dev/stune/foreground/tasks
 
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 1b1d747..22b9d6b 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -7,4 +7,4 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 04b8854..555eda4 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -13,4 +13,4 @@
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 21ff647..297468c 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -7,4 +7,4 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 257ae19..46f9f02 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -13,4 +13,4 @@
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks