Merge "crash_reporter: Add unit tests to debug builds"
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 25e8376..386f221 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -306,12 +306,14 @@
         auto it = g_poll_node_map.find(subproc_fd);
         if (it == g_poll_node_map.end()) {
             D("subproc_fd %d cleared from fd_table", subproc_fd);
+            adb_close(subproc_fd);
             return;
         }
         fdevent* subproc_fde = it->second.fde;
         if(subproc_fde->fd != subproc_fd) {
             // Already reallocated?
-            D("subproc_fd(%d) != subproc_fde->fd(%d)", subproc_fd, subproc_fde->fd);
+            LOG(FATAL) << "subproc_fd(" << subproc_fd << ") != subproc_fde->fd(" << subproc_fde->fd
+                       << ")";
             return;
         }
 
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 366ed07..e092dc4 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -183,7 +183,6 @@
     ~Subprocess();
 
     const std::string& command() const { return command_; }
-    bool is_interactive() const { return command_.empty(); }
 
     int local_socket_fd() const { return local_socket_sfd_.fd(); }
 
@@ -233,6 +232,7 @@
 }
 
 Subprocess::~Subprocess() {
+    WaitForExit();
 }
 
 bool Subprocess::ForkAndExec() {
@@ -331,7 +331,7 @@
         parent_error_sfd.Reset();
         close_on_exec(child_error_sfd.fd());
 
-        if (is_interactive()) {
+        if (command_.empty()) {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
         } else {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
@@ -408,20 +408,6 @@
         exit(-1);
     }
 
-    if (!is_interactive()) {
-        termios tattr;
-        if (tcgetattr(child_fd, &tattr) == -1) {
-            WriteFdExactly(error_sfd->fd(), "tcgetattr failed");
-            exit(-1);
-        }
-
-        cfmakeraw(&tattr);
-        if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) {
-            WriteFdExactly(error_sfd->fd(), "tcsetattr failed");
-            exit(-1);
-        }
-    }
-
     return child_fd;
 }
 
@@ -432,7 +418,6 @@
             "shell srvc %d", subprocess->local_socket_fd()));
 
     subprocess->PassDataStreams();
-    subprocess->WaitForExit();
 
     D("deleting Subprocess for PID %d", subprocess->pid());
     delete subprocess;
diff --git a/bootstat/README.md b/bootstat/README.md
index b494951..1b4bf7f 100644
--- a/bootstat/README.md
+++ b/bootstat/README.md
@@ -34,8 +34,9 @@
     $ bootstat -l
 
 bootstat logs all boot events recorded using the `-r` option to the EventLog
-using the Tron histogram. On GMS devices these logs are uploaded via Clearcut
-for aggregation and analysis.
+using the Tron histogram. These logs may be uploaded by interested parties
+for aggregation and analysis of boot time across different devices and
+versions.
 
 ## Printing boot events ##
 
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 90874f5..384f84d 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -65,7 +65,7 @@
     const std::string entry_path = path + "/" + entry_name;
     if (entry->d_type == DT_DIR) {
       DeleteDirectory(entry_path);
-    }  else {
+    } else {
       unlink(entry_path.c_str());
     }
   }
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index b55c324..11c8c0d 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -20,6 +20,7 @@
 #include <utility>
 
 #include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <brillo/syslog_logging.h>
@@ -52,20 +53,17 @@
     EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(Return());
 
     collector_.Initialize(CountCrash, IsMetrics);
-    test_dir_ = FilePath("test");
-    base::CreateDirectory(test_dir_);
+    EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
     brillo::ClearLog();
   }
 
-  void TearDown() {
-    base::DeleteFile(test_dir_, true);
-  }
-
   bool CheckHasCapacity();
 
  protected:
   CrashCollectorMock collector_;
-  FilePath test_dir_;
+
+  // Temporary directory used for tests.
+  base::ScopedTempDir test_dir_;
 };
 
 TEST_F(CrashCollectorTest, Initialize) {
@@ -74,7 +72,7 @@
 }
 
 TEST_F(CrashCollectorTest, WriteNewFile) {
-  FilePath test_file = test_dir_.Append("test_new");
+  FilePath test_file = test_dir_.path().Append("test_new");
   const char kBuffer[] = "buffer";
   EXPECT_EQ(strlen(kBuffer),
             collector_.WriteNewFile(test_file,
@@ -122,8 +120,10 @@
 
 
 bool CrashCollectorTest::CheckHasCapacity() {
-  static const char kFullMessage[] = "Crash directory test already full";
-  bool has_capacity = collector_.CheckHasCapacity(test_dir_);
+  const char* kFullMessage =
+      StringPrintf("Crash directory %s already full",
+                   test_dir_.path().value().c_str()).c_str();
+  bool has_capacity = collector_.CheckHasCapacity(test_dir_.path());
   bool has_message = FindLog(kFullMessage);
   EXPECT_EQ(has_message, !has_capacity);
   return has_capacity;
@@ -132,19 +132,22 @@
 TEST_F(CrashCollectorTest, CheckHasCapacityUsual) {
   // Test kMaxCrashDirectorySize - 1 non-meta files can be added.
   for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
-    base::WriteFile(test_dir_.Append(StringPrintf("file%d.core", i)), "", 0);
+    base::WriteFile(test_dir_.path().Append(StringPrintf("file%d.core", i)),
+                    "", 0);
     EXPECT_TRUE(CheckHasCapacity());
   }
 
   // Test an additional kMaxCrashDirectorySize - 1 meta files fit.
   for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
-    base::WriteFile(test_dir_.Append(StringPrintf("file%d.meta", i)), "", 0);
+    base::WriteFile(test_dir_.path().Append(StringPrintf("file%d.meta", i)),
+                    "", 0);
     EXPECT_TRUE(CheckHasCapacity());
   }
 
   // Test an additional kMaxCrashDirectorySize meta files don't fit.
   for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize; ++i) {
-    base::WriteFile(test_dir_.Append(StringPrintf("overage%d.meta", i)), "", 0);
+    base::WriteFile(test_dir_.path().Append(StringPrintf("overage%d.meta", i)),
+                    "", 0);
     EXPECT_FALSE(CheckHasCapacity());
   }
 }
@@ -152,50 +155,52 @@
 TEST_F(CrashCollectorTest, CheckHasCapacityCorrectBasename) {
   // Test kMaxCrashDirectorySize - 1 files can be added.
   for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
-    base::WriteFile(test_dir_.Append(StringPrintf("file.%d.core", i)), "", 0);
+    base::WriteFile(test_dir_.path().Append(StringPrintf("file.%d.core", i)),
+                    "", 0);
     EXPECT_TRUE(CheckHasCapacity());
   }
-  base::WriteFile(test_dir_.Append("file.last.core"), "", 0);
+  base::WriteFile(test_dir_.path().Append("file.last.core"), "", 0);
   EXPECT_FALSE(CheckHasCapacity());
 }
 
 TEST_F(CrashCollectorTest, CheckHasCapacityStrangeNames) {
   // Test many files with different extensions and same base fit.
   for (int i = 0; i < 5 * CrashCollector::kMaxCrashDirectorySize; ++i) {
-    base::WriteFile(test_dir_.Append(StringPrintf("a.%d", i)), "", 0);
+    base::WriteFile(test_dir_.path().Append(StringPrintf("a.%d", i)), "", 0);
     EXPECT_TRUE(CheckHasCapacity());
   }
   // Test dot files are treated as individual files.
   for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 2; ++i) {
-    base::WriteFile(test_dir_.Append(StringPrintf(".file%d", i)), "", 0);
+    base::WriteFile(test_dir_.path().Append(StringPrintf(".file%d", i)), "", 0);
     EXPECT_TRUE(CheckHasCapacity());
   }
-  base::WriteFile(test_dir_.Append("normal.meta"), "", 0);
+  base::WriteFile(test_dir_.path().Append("normal.meta"), "", 0);
   EXPECT_FALSE(CheckHasCapacity());
 }
 
 TEST_F(CrashCollectorTest, MetaData) {
   const char kMetaFileBasename[] = "generated.meta";
-  FilePath meta_file = test_dir_.Append(kMetaFileBasename);
-  FilePath payload_file = test_dir_.Append("payload-file");
+  FilePath meta_file = test_dir_.path().Append(kMetaFileBasename);
+  FilePath payload_file = test_dir_.path().Append("payload-file");
   std::string contents;
   const char kPayload[] = "foo";
   ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
   collector_.AddCrashMetaData("foo", "bar");
   collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
   EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
-  const char kExpectedMeta[] =
-      "foo=bar\n"
-      "exec_name=kernel\n"
-      "payload=test/payload-file\n"
-      "payload_size=3\n"
-      "done=1\n";
+  const std::string kExpectedMeta =
+      StringPrintf("foo=bar\n"
+          "exec_name=kernel\n"
+          "payload=%s\n"
+          "payload_size=3\n"
+          "done=1\n",
+          test_dir_.path().Append("payload-file").value().c_str());
   EXPECT_EQ(kExpectedMeta, contents);
 
   // Test target of symlink is not overwritten.
-  payload_file = test_dir_.Append("payload2-file");
+  payload_file = test_dir_.path().Append("payload2-file");
   ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
-  FilePath meta_symlink_path = test_dir_.Append("symlink.meta");
+  FilePath meta_symlink_path = test_dir_.path().Append("symlink.meta");
   ASSERT_EQ(0,
             symlink(kMetaFileBasename,
                     meta_symlink_path.value().c_str()));
@@ -221,8 +226,8 @@
 }
 
 TEST_F(CrashCollectorTest, GetLogContents) {
-  FilePath config_file = test_dir_.Append("crash_config");
-  FilePath output_file = test_dir_.Append("crash_log");
+  FilePath config_file = test_dir_.path().Append("crash_config");
+  FilePath output_file = test_dir_.path().Append("crash_log");
   const char kConfigContents[] =
       "foobar=echo hello there | \\\n  sed -e \"s/there/world/\"";
   ASSERT_TRUE(
diff --git a/crash_reporter/kernel_collector.cc b/crash_reporter/kernel_collector.cc
index 12b00b9..cb3a315 100644
--- a/crash_reporter/kernel_collector.cc
+++ b/crash_reporter/kernel_collector.cc
@@ -68,8 +68,8 @@
   " RIP  \\[<.*>\\] ([^\\+ ]+).*",  // X86_64 uses RIP for the program counter
 };
 
-COMPILE_ASSERT(arraysize(kPCRegex) == KernelCollector::kArchCount,
-               missing_arch_pc_regexp);
+static_assert(arraysize(kPCRegex) == KernelCollector::kArchCount,
+              "Missing Arch PC regexp");
 
 }  // namespace
 
diff --git a/crash_reporter/list_proxies.cc b/crash_reporter/list_proxies.cc
index d445557..3374b5f 100644
--- a/crash_reporter/list_proxies.cc
+++ b/crash_reporter/list_proxies.cc
@@ -75,13 +75,12 @@
     // Start by finding the first space (if any).
     std::string::iterator space;
     for (space = token.begin(); space != token.end(); ++space) {
-      if (IsAsciiWhitespace(*space)) {
+      if (base::IsAsciiWhitespace(*space)) {
         break;
       }
     }
 
-    std::string scheme = std::string(token.begin(), space);
-    base::StringToLowerASCII(&scheme);
+    std::string scheme = base::ToLowerASCII(std::string(token.begin(), space));
     // Chrome uses "socks" to mean socks4 and "proxy" to mean http.
     if (scheme == "socks")
       scheme += "4";
@@ -183,7 +182,7 @@
     timeout_callback_.Cancel();
     proxies_ = ParseProxyString(proxy_info);
     LOG(INFO) << "Found proxies via browser signal: "
-              << JoinString(proxies_, 'x');
+              << base::JoinString(proxies_, "x");
 
     Quit();
   }
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
index 3bdeca1..56d2704 100644
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ b/crash_reporter/unclean_shutdown_collector_test.cc
@@ -19,6 +19,7 @@
 #include <unistd.h>
 
 #include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
 #include <base/strings/string_util.h>
 #include <brillo/syslog_logging.h>
 #include <gmock/gmock.h>
@@ -32,10 +33,6 @@
 int s_crashes = 0;
 bool s_metrics = true;
 
-const char kTestDirectory[] = "test";
-const char kTestSuspended[] = "test/suspended";
-const char kTestUnclean[] = "test/unclean";
-
 void CountCrash() {
   ++s_crashes;
 }
@@ -59,12 +56,17 @@
 
     collector_.Initialize(CountCrash,
                           IsMetrics);
-    rmdir(kTestDirectory);
-    test_unclean_ = FilePath(kTestUnclean);
-    collector_.unclean_shutdown_file_ = kTestUnclean;
+
+    EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
+
+    test_directory_ = test_dir_.path().Append("test");
+    test_unclean_ = test_dir_.path().Append("test/unclean");
+
+    collector_.unclean_shutdown_file_ = test_unclean_.value().c_str();
     base::DeleteFile(test_unclean_, true);
     // Set up an alternate power manager state file as well
-    collector_.powerd_suspended_file_ = FilePath(kTestSuspended);
+    collector_.powerd_suspended_file_ =
+        test_dir_.path().Append("test/suspended");
     brillo::ClearLog();
   }
 
@@ -75,6 +77,10 @@
   }
 
   UncleanShutdownCollectorMock collector_;
+
+  // Temporary directory used for tests.
+  base::ScopedTempDir test_dir_;
+  FilePath test_directory_;
   FilePath test_unclean_;
 };
 
@@ -84,7 +90,7 @@
 }
 
 TEST_F(UncleanShutdownCollectorTest, EnableWithParent) {
-  mkdir(kTestDirectory, 0777);
+  mkdir(test_directory_.value().c_str(), 0777);
   ASSERT_TRUE(collector_.Enable());
   ASSERT_TRUE(base::PathExists(test_unclean_));
 }
@@ -133,15 +139,15 @@
 }
 
 TEST_F(UncleanShutdownCollectorTest, CantDisable) {
-  mkdir(kTestDirectory, 0700);
-  if (mkdir(kTestUnclean, 0700)) {
+  mkdir(test_directory_.value().c_str(), 0700);
+  if (mkdir(test_unclean_.value().c_str(), 0700)) {
     ASSERT_EQ(EEXIST, errno)
-        << "Error while creating directory '" << kTestUnclean
+        << "Error while creating directory '" << test_unclean_.value()
         << "': " << strerror(errno);
   }
   ASSERT_EQ(0, base::WriteFile(test_unclean_.Append("foo"), "", 0))
       << "Error while creating empty file '"
       << test_unclean_.Append("foo").value() << "': " << strerror(errno);
   ASSERT_FALSE(collector_.Disable());
-  rmdir(kTestUnclean);
+  rmdir(test_unclean_.value().c_str());
 }
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 6714f52..98d7448 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -151,8 +151,8 @@
     return false;
   }
   std::string id_substring = id_line.substr(strlen(prefix), std::string::npos);
-  std::vector<std::string> ids;
-  base::SplitString(id_substring, '\t', &ids);
+  std::vector<std::string> ids = base::SplitString(
+      id_substring, "\t", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) {
     return false;
   }
@@ -313,8 +313,8 @@
 
   uid_t uid;
   if (base::ReadFileToString(process_path.Append("status"), &status)) {
-    std::vector<std::string> status_lines;
-    base::SplitString(status, '\n', &status_lines);
+    std::vector<std::string> status_lines = base::SplitString(
+        status, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
     std::string process_state;
     if (!GetStateFromStatus(status_lines, &process_state)) {
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index 638ea34..d9c9a5b 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -65,8 +65,10 @@
                           false,
                           false,
                           "");
-    base::DeleteFile(FilePath("test"), true);
-    mkdir("test", 0777);
+
+    EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
+
+    mkdir(test_dir_.path().Append("test").value().c_str(), 0777);
     pid_ = getpid();
     brillo::ClearLog();
   }
@@ -80,13 +82,13 @@
   }
 
   std::vector<std::string> SplitLines(const std::string &lines) const {
-    std::vector<std::string> result;
-    base::SplitString(lines, '\n', &result);
-    return result;
+    return base::SplitString(lines, "\n", base::TRIM_WHITESPACE,
+                             base::SPLIT_WANT_ALL);
   }
 
   UserCollectorMock collector_;
   pid_t pid_;
+  base::ScopedTempDir test_dir_;
 };
 
 TEST_F(UserCollectorTest, ParseCrashAttributes) {
@@ -173,14 +175,15 @@
                                            &result));
   ASSERT_TRUE(FindLog(
       "Readlink failed on /does_not_exist with 2"));
-  std::string long_link;
+  std::string long_link = test_dir_.path().value();
   for (int i = 0; i < 50; ++i)
     long_link += "0123456789";
   long_link += "/gold";
 
   for (size_t len = 1; len <= long_link.size(); ++len) {
     std::string this_link;
-    static const char kLink[] = "test/this_link";
+    static const char* kLink =
+        test_dir_.path().Append("test/this_link").value().c_str();
     this_link.assign(long_link.c_str(), len);
     ASSERT_EQ(len, this_link.size());
     unlink(kLink);
@@ -341,13 +344,13 @@
 }
 
 TEST_F(UserCollectorTest, CopyOffProcFilesBadPid) {
-  FilePath container_path("test/container");
+  FilePath container_path(test_dir_.path().Append("test/container"));
   ASSERT_FALSE(collector_.CopyOffProcFiles(0, container_path));
   EXPECT_TRUE(FindLog("Path /proc/0 does not exist"));
 }
 
 TEST_F(UserCollectorTest, CopyOffProcFilesOK) {
-  FilePath container_path("test/container");
+  FilePath container_path(test_dir_.path().Append("test/container"));
   ASSERT_TRUE(collector_.CopyOffProcFiles(pid_, container_path));
   EXPECT_FALSE(FindLog("Could not copy"));
   static struct {
@@ -371,9 +374,7 @@
 }
 
 TEST_F(UserCollectorTest, ValidateProcFiles) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  FilePath container_dir = temp_dir.path();
+  FilePath container_dir = test_dir_.path();
 
   // maps file not exists (i.e. GetFileSize fails)
   EXPECT_FALSE(collector_.ValidateProcFiles(container_dir));
@@ -392,9 +393,7 @@
 }
 
 TEST_F(UserCollectorTest, ValidateCoreFile) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  FilePath container_dir = temp_dir.path();
+  FilePath container_dir = test_dir_.path();
   FilePath core_file = container_dir.Append("core");
 
   // Core file does not exist
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d2291bb..35f1a9e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -418,20 +418,32 @@
     while (1) { pause(); }  // never reached
 }
 
-static void import_late() {
-    static const std::vector<std::string> init_directories = {
-        "/system/etc/init",
-        "/vendor/etc/init",
-        "/odm/etc/init"
-    };
-
+/* Imports .rc files from the specified paths. Default ones are applied if none is given.
+ *
+ * start_index: index of the first path in the args list
+ */
+static void import_late(const std::vector<std::string>& args, size_t start_index) {
     Parser& parser = Parser::GetInstance();
-    for (const auto& dir : init_directories) {
-        parser.ParseConfig(dir.c_str());
+    if (args.size() <= start_index) {
+        // Use the default set if no path is given
+        static const std::vector<std::string> init_directories = {
+            "/system/etc/init",
+            "/vendor/etc/init",
+            "/odm/etc/init"
+        };
+
+        for (const auto& dir : init_directories) {
+            parser.ParseConfig(dir);
+        }
+    } else {
+        for (size_t i = start_index; i < args.size(); ++i) {
+            parser.ParseConfig(args[i]);
+        }
     }
 }
 
-/*
+/* mount_all <fstab> [ <path> ]*
+ *
  * This function might request a reboot, in which case it will
  * not return.
  */
@@ -478,7 +490,8 @@
         return -1;
     }
 
-    import_late();
+    /* Paths of .rc files are specified at the 2nd argument and beyond */
+    import_late(args, 2);
 
     if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
         property_set("vold.decrypt", "trigger_encryption");
@@ -900,7 +913,7 @@
         {"load_system_props",       {0,     0,    do_load_system_props}},
         {"loglevel",                {1,     1,    do_loglevel}},
         {"mkdir",                   {1,     4,    do_mkdir}},
-        {"mount_all",               {1,     1,    do_mount_all}},
+        {"mount_all",               {1,     kMax, do_mount_all}},
         {"mount",                   {3,     kMax, do_mount}},
         {"powerctl",                {1,     1,    do_powerctl}},
         {"restart",                 {1,     1,    do_restart}},
diff --git a/init/readme.txt b/init/readme.txt
index bacd6bd..5a1cf44 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -49,6 +49,8 @@
       actions or daemons needed for motion sensor or other peripheral
       functionality.
 
+One may specify paths in the mount_all command line to have it import
+.rc files at the specified paths instead of the default ones described above.
 
 Actions
 -------
@@ -263,8 +265,10 @@
    owned by the root user and root group. If provided, the mode, owner and group
    will be updated if the directory exists already.
 
-mount_all <fstab>
-   Calls fs_mgr_mount_all on the given fs_mgr-format fstab.
+mount_all <fstab> [ <path> ]*
+   Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
+   at the specified paths (e.g., on the partitions just mounted). Refer to the
+   section of "Init .rc Files" for detail.
 
 mount <type> <device> <dir> [ <flag> ]* [<options>]
    Attempt to mount the named device at the directory <dir>
@@ -358,7 +362,8 @@
 
 There are only two times where the init executable imports .rc files,
    1) When it imports /init.rc during initial boot
-   2) When it imports /{system,vendor,odm}/etc/init/ during mount_all
+   2) When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified
+      paths during mount_all
 
 
 Properties
diff --git a/liblog/logprint.c b/liblog/logprint.c
index bd36cdd..4ef62a1 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -1488,7 +1488,7 @@
         strcat(p, suffixBuf);
         p += suffixLen;
     } else {
-        while(pm < (entry->message + entry->messageLen)) {
+        do {
             const char *lineStart;
             size_t lineLen;
             lineStart = pm;
@@ -1510,7 +1510,7 @@
             p += suffixLen;
 
             if (*pm == '\n') pm++;
-        }
+        } while (pm < (entry->message + entry->messageLen));
     }
 
     if (p_outLength != NULL) {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 50afc5f..a936455 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -165,6 +165,133 @@
     android_logger_list_close(logger_list);
 }
 
+static inline int32_t get4LE(const char* src)
+{
+    return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+TEST(liblog, __android_log_bswrite) {
+    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)));
+
+    static const char buffer[] = "Hello World";
+    log_time ts(android_log_clockid());
+
+    ASSERT_LT(0, __android_log_bswrite(0, buffer));
+    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)
+         || (log_msg.entry.len != (4 + 1 + 4 + sizeof(buffer) - 1))
+         || (log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        if (eventData[4] != EVENT_TYPE_STRING) {
+            continue;
+        }
+
+        int len = get4LE(eventData + 4 + 1);
+        if (len == (sizeof(buffer) - 1)) {
+            ++count;
+
+            AndroidLogFormat *logformat = android_log_format_new();
+            EXPECT_TRUE(NULL != logformat);
+            AndroidLogEntry entry;
+            char msgBuf[1024];
+            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
+                                                            &entry,
+                                                            NULL,
+                                                            msgBuf,
+                                                            sizeof(msgBuf)));
+            fflush(stderr);
+            EXPECT_EQ(31, android_log_printLogLine(logformat, fileno(stderr), &entry));
+            android_log_format_free(logformat);
+        }
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, __android_log_bswrite__empty_string) {
+    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)));
+
+    static const char buffer[] = "";
+    log_time ts(android_log_clockid());
+
+    ASSERT_LT(0, __android_log_bswrite(0, buffer));
+    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)
+         || (log_msg.entry.len != (4 + 1 + 4))
+         || (log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        if (eventData[4] != EVENT_TYPE_STRING) {
+            continue;
+        }
+
+        int len = get4LE(eventData + 4 + 1);
+        if (len == 0) {
+            ++count;
+
+            AndroidLogFormat *logformat = android_log_format_new();
+            EXPECT_TRUE(NULL != logformat);
+            AndroidLogEntry entry;
+            char msgBuf[1024];
+            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
+                                                            &entry,
+                                                            NULL,
+                                                            msgBuf,
+                                                            sizeof(msgBuf)));
+            fflush(stderr);
+            EXPECT_EQ(20, android_log_printLogLine(logformat, fileno(stderr), &entry));
+            android_log_format_free(logformat);
+        }
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
 TEST(liblog, __security) {
     static const char persist_key[] = "persist.logd.security";
     static const char readonly_key[] = "ro.device_owner";
@@ -1106,11 +1233,6 @@
     property_set(key + base_offset, hold[3]);
 }
 
-static inline int32_t get4LE(const char* src)
-{
-    return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
-}
-
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
     const int TAG = 123456781;
     const char SUBTAG[] = "test-subtag";
diff --git a/metricsd/collectors/cpu_usage_collector.cc b/metricsd/collectors/cpu_usage_collector.cc
index 05934b4..9b0bb34 100644
--- a/metricsd/collectors/cpu_usage_collector.cc
+++ b/metricsd/collectors/cpu_usage_collector.cc
@@ -104,14 +104,15 @@
                                       uint64_t *user_ticks,
                                       uint64_t *user_nice_ticks,
                                       uint64_t *system_ticks) {
-  std::vector<std::string> proc_stat_lines;
-  base::SplitString(stat_content, '\n', &proc_stat_lines);
+  std::vector<std::string> proc_stat_lines = base::SplitString(
+      stat_content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   if (proc_stat_lines.empty()) {
     LOG(WARNING) << "No lines found in " << kMetricsProcStatFileName;
     return false;
   }
-  std::vector<std::string> proc_stat_totals;
-  base::SplitStringAlongWhitespace(proc_stat_lines[0], &proc_stat_totals);
+  std::vector<std::string> proc_stat_totals =
+      base::SplitString(proc_stat_lines[0], base::kWhitespaceASCII,
+                        base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
   if (proc_stat_totals.size() != kMetricsProcStatFirstLineItemsCount ||
       proc_stat_totals[0] != "cpu" ||
diff --git a/metricsd/libmetrics-334380.gyp b/metricsd/libmetrics-369476.gyp
similarity index 72%
rename from metricsd/libmetrics-334380.gyp
rename to metricsd/libmetrics-369476.gyp
index 9771821..b545d35 100644
--- a/metricsd/libmetrics-334380.gyp
+++ b/metricsd/libmetrics-369476.gyp
@@ -1,6 +1,6 @@
 {
   'variables': {
-    'libbase_ver': 334380,
+    'libbase_ver': 369476,
   },
   'includes': [
     'libmetrics.gypi',
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index 2cf2338..ec7e040 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -534,18 +534,20 @@
 
 bool MetricsCollector::FillMeminfo(const string& meminfo_raw,
                                     vector<MeminfoRecord>* fields) {
-  vector<string> lines;
-  unsigned int nlines = Tokenize(meminfo_raw, "\n", &lines);
+  vector<std::string> lines =
+      base::SplitString(meminfo_raw, "\n", base::KEEP_WHITESPACE,
+                        base::SPLIT_WANT_NONEMPTY);
 
   // Scan meminfo output and collect field values.  Each field name has to
   // match a meminfo entry (case insensitive) after removing non-alpha
   // characters from the entry.
-  unsigned int ifield = 0;
-  for (unsigned int iline = 0;
-       iline < nlines && ifield < fields->size();
+  size_t ifield = 0;
+  for (size_t iline = 0;
+       iline < lines.size() && ifield < fields->size();
        iline++) {
-    vector<string> tokens;
-    Tokenize(lines[iline], ": ", &tokens);
+    vector<string> tokens =
+        base::SplitString(lines[iline], ": ", base::KEEP_WHITESPACE,
+                          base::SPLIT_WANT_NONEMPTY);
     if (strcmp((*fields)[ifield].match, tokens[0].c_str()) == 0) {
       // Name matches. Parse value and save.
       if (!base::StringToInt(tokens[1], &(*fields)[ifield].value)) {
diff --git a/metricsd/metrics_collector_main.cc b/metricsd/metrics_collector_main.cc
index d7aaaf5..14bb935 100644
--- a/metricsd/metrics_collector_main.cc
+++ b/metricsd/metrics_collector_main.cc
@@ -41,7 +41,8 @@
   }
   dev_path = dev_path_cstr;
   // Check that rootdev begins with "/dev/block/".
-  if (!base::StartsWithASCII(dev_path, dev_prefix, false)) {
+  if (!base::StartsWith(dev_path, dev_prefix,
+                        base::CompareCase::INSENSITIVE_ASCII)) {
     LOG(WARNING) << "unexpected root device " << dev_path;
     return "";
   }
diff --git a/metricsd/uploader/metricsd_service_runner.cc b/metricsd/uploader/metricsd_service_runner.cc
index 2834977..5a759d3 100644
--- a/metricsd/uploader/metricsd_service_runner.cc
+++ b/metricsd/uploader/metricsd_service_runner.cc
@@ -54,7 +54,7 @@
 
 void MetricsdServiceRunner::Stop() {
   message_loop_for_io_->PostTask(FROM_HERE,
-                                 message_loop_for_io_->QuitClosure());
+                                 message_loop_for_io_->QuitWhenIdleClosure());
 
   thread_->join();
 }