init: add exec_start command
am: b27004aa05

Change-Id: I98ce17c11621eece46728aa94dc64f54273e5a99
diff --git a/.clang-format-2 b/.clang-format-2
index aab4665..41591ce 100644
--- a/.clang-format-2
+++ b/.clang-format-2
@@ -1,4 +1,5 @@
 BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
 ColumnLimit: 100
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
diff --git a/.clang-format-4 b/.clang-format-4
index 1497447..ae4a451 100644
--- a/.clang-format-4
+++ b/.clang-format-4
@@ -1,5 +1,6 @@
 BasedOnStyle: Google
 AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
 ColumnLimit: 100
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
diff --git a/adb/Android.mk b/adb/Android.mk
index 8a43e37..e841205 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -124,12 +124,11 @@
     adbd_auth.cpp \
     jdwp_service.cpp \
 
-LOCAL_C_INCLUDES := system/core/qemu_pipe/include
 LOCAL_SANITIZE := $(adb_target_sanitize)
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libqemu_pipe libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libadbd_usb
 
@@ -362,7 +361,6 @@
 LOCAL_STATIC_LIBRARIES := \
     libadbd \
     libbase \
-    libqemu_pipe \
     libbootloader_message \
     libfs_mgr \
     libfec \
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 12b98ba..4198a52 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -289,7 +289,7 @@
 #define open    adb_open
 #define read    adb_read
 #define write   adb_write
-#include <qemu_pipe.h>
+#include <system/qemu_pipe.h>
 #undef open
 #undef read
 #undef write
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4de5e57..041586c 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -62,15 +62,14 @@
 // Waits for the system property `key` to have the value `expected_value`.
 // Times out after `relative_timeout`.
 // Returns true on success, false on timeout.
-bool WaitForProperty(const std::string& key,
-                     const std::string& expected_value,
-                     std::chrono::milliseconds relative_timeout);
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
+                     std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
 
 // Waits for the system property `key` to be created.
 // Times out after `relative_timeout`.
 // Returns true on success, false on timeout.
-bool WaitForPropertyCreation(const std::string& key,
-                             std::chrono::milliseconds relative_timeout);
+bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout =
+                                                         std::chrono::milliseconds::max());
 
 } // namespace base
 } // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index 32c0128..816bca0 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -101,22 +101,24 @@
 }
 
 // TODO: chrono_utils?
-static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
+static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
   auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
   auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
   ts.tv_sec = s.count();
   ts.tv_nsec = ns.count();
 }
 
+// TODO: boot_clock?
 using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
 
-static void UpdateTimeSpec(timespec& ts,
-                           const AbsTime& timeout) {
+static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout,
+                           const AbsTime& start_time) {
   auto now = std::chrono::steady_clock::now();
-  auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
-  if (remaining_timeout < 0ns) {
+  auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+  if (time_elapsed >= relative_timeout) {
     ts = { 0, 0 };
   } else {
+    auto remaining_timeout = relative_timeout - time_elapsed;
     DurationToTimeSpec(ts, remaining_timeout);
   }
 }
@@ -127,11 +129,7 @@
 // Returns nullptr on timeout.
 static const prop_info* WaitForPropertyCreation(const std::string& key,
                                                 const std::chrono::milliseconds& relative_timeout,
-                                                AbsTime& absolute_timeout) {
-  // TODO: boot_clock?
-  auto now = std::chrono::steady_clock::now();
-  absolute_timeout = now + relative_timeout;
-
+                                                const AbsTime& start_time) {
   // Find the property's prop_info*.
   const prop_info* pi;
   unsigned global_serial = 0;
@@ -139,17 +137,16 @@
     // The property doesn't even exist yet.
     // Wait for a global change and then look again.
     timespec ts;
-    UpdateTimeSpec(ts, absolute_timeout);
+    UpdateTimeSpec(ts, relative_timeout, start_time);
     if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
   }
   return pi;
 }
 
-bool WaitForProperty(const std::string& key,
-                     const std::string& expected_value,
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
                      std::chrono::milliseconds relative_timeout) {
-  AbsTime absolute_timeout;
-  const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
+  auto start_time = std::chrono::steady_clock::now();
+  const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time);
   if (pi == nullptr) return false;
 
   WaitForPropertyData data;
@@ -162,7 +159,7 @@
     if (data.done) return true;
 
     // It didn't, so wait for the property to change before checking again.
-    UpdateTimeSpec(ts, absolute_timeout);
+    UpdateTimeSpec(ts, relative_timeout, start_time);
     uint32_t unused;
     if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
   }
@@ -170,8 +167,8 @@
 
 bool WaitForPropertyCreation(const std::string& key,
                              std::chrono::milliseconds relative_timeout) {
-  AbsTime absolute_timeout;
-  return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
+  auto start_time = std::chrono::steady_clock::now();
+  return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
 }
 
 }  // namespace base
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index 1bbe482..de5f3dc 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -151,6 +151,38 @@
   ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
 }
 
+TEST(properties, WaitForProperty_MaxTimeout) {
+  std::atomic<bool> flag{false};
+  std::thread thread([&]() {
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+    while (!flag) std::this_thread::yield();
+    std::this_thread::sleep_for(500ms);
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+  });
+
+  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+  flag = true;
+  // Test that this does not immediately return false due to overflow issues with the timeout.
+  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
+  thread.join();
+}
+
+TEST(properties, WaitForProperty_NegativeTimeout) {
+  std::atomic<bool> flag{false};
+  std::thread thread([&]() {
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+    while (!flag) std::this_thread::yield();
+    std::this_thread::sleep_for(500ms);
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+  });
+
+  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+  flag = true;
+  // Assert that this immediately returns with a negative timeout
+  ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
+  thread.join();
+}
+
 TEST(properties, WaitForPropertyCreation) {
   std::thread thread([&]() {
     std::this_thread::sleep_for(100ms);
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 2d6c7f5..024bc3d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -161,6 +161,7 @@
     target: {
         android: {
             srcs: [
+                "client/debuggerd_client_test.cpp",
                 "debuggerd_test.cpp",
                 "util.cpp"
             ],
@@ -171,6 +172,7 @@
         "libbacktrace",
         "libbase",
         "libcutils",
+        "libdebuggerd_client",
     ],
 
     static_libs: [
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index f2975d1..b9fb512 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -19,12 +19,14 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/poll.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <chrono>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
@@ -33,6 +35,8 @@
 #include <debuggerd/protocol.h>
 #include <debuggerd/util.h>
 
+using namespace std::chrono_literals;
+
 using android::base::unique_fd;
 
 static bool send_signal(pid_t pid, bool backtrace) {
@@ -45,28 +49,31 @@
   return true;
 }
 
+template <typename Duration>
+static void populate_timeval(struct timeval* tv, const Duration& duration) {
+  auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
+  auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration - seconds);
+  tv->tv_sec = static_cast<long>(seconds.count());
+  tv->tv_usec = static_cast<long>(microseconds.count());
+}
+
 bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type,
                             int timeout_ms) {
   LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
   unique_fd sockfd;
   const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
-  auto set_timeout = [timeout_ms, &sockfd, &end]() {
+  auto time_left = [timeout_ms, &end]() { return end - std::chrono::steady_clock::now(); };
+  auto set_timeout = [timeout_ms, &time_left](int sockfd) {
     if (timeout_ms <= 0) {
       return true;
     }
 
-    auto now = std::chrono::steady_clock::now();
-    if (now > end) {
+    auto remaining = time_left();
+    if (remaining < decltype(remaining)::zero()) {
       return false;
     }
-
-    auto time_left = std::chrono::duration_cast<std::chrono::microseconds>(end - now);
-    auto seconds = std::chrono::duration_cast<std::chrono::seconds>(time_left);
-    auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(time_left - seconds);
-    struct timeval timeout = {
-      .tv_sec = static_cast<long>(seconds.count()),
-      .tv_usec = static_cast<long>(microseconds.count()),
-    };
+    struct timeval timeout;
+    populate_timeval(&timeout, remaining);
 
     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
       return false;
@@ -84,7 +91,7 @@
     return false;
   }
 
-  if (!set_timeout()) {
+  if (!set_timeout(sockfd)) {
     PLOG(ERROR) << "libdebugger_client: failed to set timeout";
     return false;
   }
@@ -96,11 +103,19 @@
   }
 
   InterceptRequest req = {.pid = pid };
-  if (!set_timeout()) {
+  if (!set_timeout(sockfd)) {
     PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+    return false;
   }
 
-  if (send_fd(sockfd.get(), &req, sizeof(req), std::move(output_fd)) != sizeof(req)) {
+  // Create an intermediate pipe to pass to the other end.
+  unique_fd pipe_read, pipe_write;
+  if (!Pipe(&pipe_read, &pipe_write)) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to create pipe";
+    return false;
+  }
+
+  if (send_fd(sockfd.get(), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
     PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
     return false;
   }
@@ -108,8 +123,9 @@
   bool backtrace = dump_type == kDebuggerdBacktrace;
   send_signal(pid, backtrace);
 
-  if (!set_timeout()) {
-    PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+  if (!set_timeout(sockfd)) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to set timeout";
+    return false;
   }
 
   InterceptResponse response;
@@ -127,6 +143,48 @@
   if (response.success != 1) {
     response.error_message[sizeof(response.error_message) - 1] = '\0';
     LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
+    return false;
+  }
+
+  // Forward output from the pipe to the output fd.
+  while (true) {
+    auto remaining_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_left());
+    if (remaining_ms <= 1ms) {
+      LOG(ERROR) << "libdebuggerd_client: timeout expired";
+      return false;
+    }
+
+    struct pollfd pfd = {
+        .fd = pipe_read.get(), .events = POLLIN, .revents = 0,
+    };
+
+    rc = poll(&pfd, 1, remaining_ms.count());
+    if (rc == -1) {
+      if (errno == EINTR) {
+        continue;
+      } else {
+        PLOG(ERROR) << "libdebuggerd_client: error while polling";
+        return false;
+      }
+    } else if (rc == 0) {
+      LOG(ERROR) << "libdebuggerd_client: timeout expired";
+      return false;
+    }
+
+    char buf[1024];
+    rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), buf, sizeof(buf)));
+    if (rc == 0) {
+      // Done.
+      break;
+    } else if (rc == -1) {
+      PLOG(ERROR) << "libdebuggerd_client: error while reading";
+      return false;
+    }
+
+    if (!android::base::WriteFully(output_fd.get(), buf, rc)) {
+      PLOG(ERROR) << "libdebuggerd_client: error while writing";
+      return false;
+    }
   }
 
   LOG(INFO) << "libdebuggerd_client: done dumping process " << pid;
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
new file mode 100644
index 0000000..86d0314
--- /dev/null
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017, 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 <debuggerd/client.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include <debuggerd/util.h>
+
+using namespace std::chrono_literals;
+using android::base::unique_fd;
+
+TEST(debuggerd_client, race) {
+  static constexpr int THREAD_COUNT = 1024;
+  pid_t forkpid = fork();
+
+  ASSERT_NE(-1, forkpid);
+
+  if (forkpid == 0) {
+    // Spawn a bunch of threads, to make crash_dump take longer.
+    std::vector<std::thread> threads;
+    for (int i = 0; i < THREAD_COUNT; ++i) {
+      threads.emplace_back([]() {
+        while (true) {
+          std::this_thread::sleep_for(60s);
+        }
+      });
+    }
+
+    std::this_thread::sleep_for(60s);
+    exit(0);
+  }
+
+  unique_fd pipe_read, pipe_write;
+  ASSERT_TRUE(Pipe(&pipe_read, &pipe_write));
+
+  // 64 kB should be enough for everyone.
+  constexpr int PIPE_SIZE = 64 * 1024 * 1024;
+  ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE));
+
+  // Wait for a bit to let the child spawn all of its threads.
+  std::this_thread::sleep_for(250ms);
+
+  ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(pipe_write), kDebuggerdBacktrace, 10000));
+  // Immediately kill the forked child, to make sure that the dump didn't return early.
+  ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno);
+
+  // Check the output.
+  std::string result;
+  ASSERT_TRUE(android::base::ReadFdToString(pipe_read.get(), &result));
+
+  // Look for "----- end <PID> -----"
+  int found_end = 0;
+
+  std::string expected_end = android::base::StringPrintf("----- end %d -----", forkpid);
+
+  std::vector<std::string> lines = android::base::Split(result, "\n");
+  for (const std::string& line : lines) {
+    if (line == expected_end) {
+      ++found_end;
+    }
+  }
+
+  EXPECT_EQ(1, found_end) << "\nOutput: \n" << result;
+}
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
index be4d2dd..66e5e58 100644
--- a/demangle/demangle.cpp
+++ b/demangle/demangle.cpp
@@ -20,22 +20,25 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <cctype>
 #include <string>
 
 #include <demangle.h>
 
 extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
 
-void usage(const char* prog_name) {
-  printf("Usage: %s [-c] <NAME_TO_DEMANGLE>\n", prog_name);
-  printf("  -c\n");
-  printf("    Compare the results of __cxa_demangle against the current\n");
-  printf("    demangler.\n");
+static void Usage(const char* prog_name) {
+  printf("usage: %s [-c] [NAME_TO_DEMANGLE...]\n", prog_name);
+  printf("\n");
+  printf("Demangles C++ mangled names if supplied on the command-line, or found\n");
+  printf("reading from stdin otherwise.\n");
+  printf("\n");
+  printf("-c\tCompare against __cxa_demangle\n");
+  printf("\n");
 }
 
-std::string DemangleWithCxa(const char* name) {
+static std::string DemangleWithCxa(const char* name) {
   const char* cxa_demangle = __cxa_demangle(name, nullptr, nullptr, nullptr);
-
   if (cxa_demangle == nullptr) {
     return name;
   }
@@ -54,6 +57,49 @@
   return demangled_str;
 }
 
+static void Compare(const char* name, const std::string& demangled_name) {
+  std::string cxa_demangled_name(DemangleWithCxa(name));
+  if (cxa_demangled_name != demangled_name) {
+    printf("\nMismatch!\n");
+    printf("\tmangled name: %s\n", name);
+    printf("\tour demangle: %s\n", demangled_name.c_str());
+    printf("\tcxa demangle: %s\n", cxa_demangled_name.c_str());
+    exit(1);
+  }
+}
+
+static int Filter(bool compare) {
+  char* line = nullptr;
+  size_t line_length = 0;
+
+  while ((getline(&line, &line_length, stdin)) != -1) {
+    char* p = line;
+    char* name;
+    while ((name = strstr(p, "_Z")) != nullptr) {
+      // Output anything before the identifier.
+      *name = 0;
+      printf("%s", p);
+      *name = '_';
+
+      // Extract the identifier.
+      p = name;
+      while (*p && (std::isalnum(*p) || *p == '_' || *p == '.' || *p == '$')) ++p;
+
+      // Demangle and output.
+      std::string identifier(name, p);
+      std::string demangled_name = demangle(identifier.c_str());
+      printf("%s", demangled_name.c_str());
+
+      if (compare) Compare(identifier.c_str(), demangled_name);
+    }
+    // Output anything after the last identifier.
+    printf("%s", p);
+  }
+
+  free(line);
+  return 0;
+}
+
 int main(int argc, char** argv) {
 #ifdef __BIONIC__
   const char* prog_name = getprogname();
@@ -67,31 +113,21 @@
     if (opt_char == 'c') {
       compare = true;
     } else {
-      usage(prog_name);
+      Usage(prog_name);
       return 1;
     }
   }
-  if (optind >= argc || argc - optind != 1) {
-    printf("Must supply a single argument.\n\n");
-    usage(prog_name);
-    return 1;
-  }
-  const char* name = argv[optind];
 
-  std::string demangled_name = demangle(name);
+  // With no arguments, act as a filter.
+  if (optind == argc) return Filter(compare);
 
-  printf("%s\n", demangled_name.c_str());
+  // Otherwise demangle each argument.
+  while (optind < argc) {
+    const char* name = argv[optind++];
+    std::string demangled_name = demangle(name);
+    printf("%s\n", demangled_name.c_str());
 
-  if (compare) {
-    std::string cxa_demangle_str(DemangleWithCxa(name));
-
-    if (cxa_demangle_str != demangled_name) {
-      printf("Mismatch\n");
-      printf("cxa demangle: %s\n", cxa_demangle_str.c_str());
-      return 1;
-    } else {
-      printf("Match\n");
-    }
+    if (compare) Compare(name, demangled_name);
   }
   return 0;
 }
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index 1c7da30..b3c0cd7 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -31,7 +31,7 @@
 FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;
 
 // Supported fingerprint HAL version
-static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1);
 
 FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {
 
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index dd8c7e7..2c14c9b 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -78,7 +78,7 @@
     // access. fs_mgr_test_access() will test a few iterations if the
     // path doesn't exist yet.
     if (fs_mgr_test_access(path.c_str()) < 0) {
-        return AVB_IO_RESULT_ERROR_IO;
+        return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
     }
 
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index 5b2f218..cffa6ce 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -56,7 +56,7 @@
             return true;
         }
 
-        LERROR << "Error finding '" << key << "' in device tree";
+        LINFO << "Error finding '" << key << "' in device tree";
     }
 
     return false;
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index d4a92e5..96bda07 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -166,7 +166,14 @@
                     enrolled_password_handle, enrolled_password_handle_length);
         }
 
-        if (ret == 0) {
+        if (ret == GATEKEEPER_RESPONSE_OK && (*enrolled_password_handle == nullptr ||
+            *enrolled_password_handle_length != sizeof(password_handle_t))) {
+            ret = GATEKEEPER_RESPONSE_ERROR;
+            ALOGE("HAL: password_handle=%p size_of_handle=%" PRIu32 "\n",
+                  *enrolled_password_handle, *enrolled_password_handle_length);
+        }
+
+        if (ret == GATEKEEPER_RESPONSE_OK) {
             gatekeeper::password_handle_t *handle =
                     reinterpret_cast<gatekeeper::password_handle_t *>(*enrolled_password_handle);
             store_sid(uid, handle->user_id);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 7c5e35b..b292725 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -21,6 +21,10 @@
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+LOCAL_SHARED_LIBRARIES += libsuspend
+endif
 LOCAL_SRC_FILES := \
     healthd_mode_android.cpp \
     healthd_mode_charger.cpp \
@@ -90,6 +94,14 @@
 
 LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
 
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+endif
+
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+endif
+
 LOCAL_STATIC_LIBRARIES := \
     libhealthd_internal \
     libbatterymonitor \
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 20a6bf6..aa6735d 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -35,9 +35,19 @@
 
 using namespace android;
 
-// Periodic chores intervals in seconds
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
+  // Periodic chores fast interval in seconds
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+#else
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+#endif
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
+  // Periodic chores fast interval in seconds
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+#else
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+#endif
 
 static struct healthd_config healthd_config = {
     .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
@@ -143,10 +153,14 @@
     struct android::BatteryProperties* /*props*/) {
 }
 
-int healthd_register_event(int fd, void (*handler)(uint32_t)) {
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
     struct epoll_event ev;
 
-    ev.events = EPOLLIN | EPOLLWAKEUP;
+    ev.events = EPOLLIN;
+
+    if (wakeup == EVENT_WAKEUP_FD)
+        ev.events |= EPOLLWAKEUP;
+
     ev.data.ptr = (void *)handler;
     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
         KLOG_ERROR(LOG_TAG,
@@ -252,7 +266,7 @@
     }
 
     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-    if (healthd_register_event(uevent_fd, uevent_event))
+    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
         KLOG_ERROR(LOG_TAG,
                    "register for uevent events failed\n");
 }
@@ -275,7 +289,7 @@
         return;
     }
 
-    if (healthd_register_event(wakealarm_fd, wakealarm_event))
+    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
         KLOG_ERROR(LOG_TAG,
                    "Registration of wakealarm event failed\n");
 
@@ -283,17 +297,22 @@
 }
 
 static void healthd_mainloop(void) {
+    int nevents = 0;
     while (1) {
         struct epoll_event events[eventct];
-        int nevents;
         int timeout = awake_poll_interval;
         int mode_timeout;
 
+        /* Don't wait for first timer timeout to run periodic chores */
+        if (!nevents)
+            periodic_chores();
+
+        healthd_mode_ops->heartbeat();
+
         mode_timeout = healthd_mode_ops->preparetowait();
         if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
             timeout = mode_timeout;
         nevents = epoll_wait(epollfd, events, eventct, timeout);
-
         if (nevents == -1) {
             if (errno == EINTR)
                 continue;
@@ -305,11 +324,6 @@
             if (events[n].data.ptr)
                 (*(void (*)(int))events[n].data.ptr)(events[n].events);
         }
-
-        if (!nevents)
-            periodic_chores();
-
-        healthd_mode_ops->heartbeat();
     }
 
     return;
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 2f69372..91774c6 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -343,14 +343,19 @@
 
 static void draw_percent(const animation& anim)
 {
-    if (anim.cur_level <= 0 || anim.cur_status != BATTERY_STATUS_CHARGING) return;
+    int cur_level = anim.cur_level;
+    if (anim.cur_status == BATTERY_STATUS_FULL) {
+        cur_level = 100;
+    }
+
+    if (cur_level <= 0) return;
 
     const animation::text_field& field = anim.text_percent;
     if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
         return;
     }
 
-    std::string str = base::StringPrintf("%d%%", anim.cur_level);
+    std::string str = base::StringPrintf("%d%%", cur_level);
 
     int x, y;
     determine_xy(field, str.size(), &x, &y);
@@ -840,7 +845,7 @@
                             std::placeholders::_2));
     if (!ret) {
         epollfd = ev_get_epollfd();
-        healthd_register_event(epollfd, charger_event_handler);
+        healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
     }
 
     struct animation* anim = init_animation();
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index 34ea55f..17efbd6 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -73,9 +73,14 @@
     bool (*screen_on)(android::BatteryProperties *props);
 };
 
+enum EventWakeup {
+    EVENT_NO_WAKEUP_FD,
+    EVENT_WAKEUP_FD,
+};
+
 // Global helper functions
 
-int healthd_register_event(int fd, void (*handler)(uint32_t));
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
 void healthd_battery_update();
 android::status_t healthd_get_property(int id,
     struct android::BatteryProperty *val);
diff --git a/include/system/qemu_pipe.h b/include/system/qemu_pipe.h
new file mode 100644
index 0000000..af25079
--- /dev/null
+++ b/include/system/qemu_pipe.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 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_INCLUDE_SYSTEM_QEMU_PIPE_H
+#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+#  define  QEMU_PIPE_DEBUG(...)   (void)0
+#endif
+
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+//
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL  -> unknown/unsupported pipeName
+// ENOSYS  -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+static __inline__ int qemu_pipe_open(const char* pipeName) {
+    // Sanity check.
+    if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+    if (fd < 0) {
+        QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+                        strerror(errno));
+        return -1;
+    }
+
+    // Write the pipe name, *including* the trailing zero which is necessary.
+    size_t pipeNameLen = strlen(pipeName);
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
+    if (ret != (ssize_t)pipeNameLen + 1) {
+        QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
+                        __FUNCTION__, pipeName, strerror(errno));
+        if (ret == 0) {
+            errno = ECONNRESET;
+        } else if (ret > 0) {
+            errno = EINVAL;
+        }
+        return -1;
+    }
+    return fd;
+}
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+static int __inline__ qemu_pipe_frame_send(int fd,
+                                           const void* buff,
+                                           size_t len) {
+    char header[5];
+    snprintf(header, sizeof(header), "%04zx", len);
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
+    if (ret != 4) {
+        QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+        return -1;
+    }
+    ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
+    if (ret != (ssize_t)len) {
+        QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+    char header[5];
+    ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
+    if (ret != 4) {
+        QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+        return -1;
+    }
+    header[4] = '\0';
+    size_t size;
+    if (sscanf(header, "%04zx", &size) != 1) {
+        QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+        return -1;
+    }
+    if (size > len) {
+        QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+                        len);
+        return -1;
+    }
+    ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
+    if (ret != (ssize_t)size) {
+        QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+                        strerror(errno));
+        return -1;
+    }
+    return size;
+}
+
+#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/init/README.md b/init/README.md
index 1b2690c..0d8f495 100644
--- a/init/README.md
+++ b/init/README.md
@@ -192,16 +192,17 @@
 `oneshot`
 > Do not restart the service when it exits.
 
-`class <name>`
-> Specify a class name for the service.  All services in a
+`class <name> [ <name>\* ]`
+> Specify class names for the service.  All services in a
   named class may be started or stopped together.  A service
   is in the class "default" if one is not specified via the
-  class option.
+  class option. Additional classnames beyond the (required) first
+  one are used to group services.
 
 `onrestart`
 > Execute a Command (see below) when service restarts.
 
-`writepid <file...>`
+`writepid <file> [ <file>\* ]`
 > Write the child's pid to the given files when it forks. Meant for
   cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
   system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
@@ -279,6 +280,9 @@
   currently running, without disabling them. They can be restarted
   later using `class_start`.
 
+`class_restart <serviceclass>`
+> Restarts all services of the specified class.
+
 `copy <src> <dst>`
 > Copies a file. Similar to write, but useful for binary/large
   amounts of data.
@@ -364,7 +368,8 @@
   "sys.powerctl" system property, used to implement rebooting.
 
 `restart <service>`
-> Like stop, but doesn't disable the service.
+> Stops and restarts a running service, does nothing if the service is currently
+  restarting, otherwise, it just starts the service.
 
 `restorecon <path> [ <path>\* ]`
 > Restore the file named by _path_ to the security context specified
diff --git a/init/action.cpp b/init/action.cpp
index 1bba0f2..2ccf0bc 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -18,14 +18,14 @@
 
 #include <errno.h>
 
-#include <android-base/strings.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "builtins.h"
 #include "error.h"
 #include "init_parser.h"
 #include "log.h"
-#include "property_service.h"
 #include "util.h"
 
 using android::base::Join;
@@ -219,9 +219,8 @@
                 found = true;
             }
         } else {
-            std::string prop_val = property_get(trigger_name.c_str());
-            if (prop_val.empty() || (trigger_value != "*" &&
-                                     trigger_value != prop_val)) {
+            std::string prop_val = android::base::GetProperty(trigger_name, "");
+            if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) {
                 return false;
             }
         }
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 4a9c32e..beabea1 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -16,8 +16,6 @@
 
 #include "bootchart.h"
 
-#include "property_service.h"
-
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -39,6 +37,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 
 using android::base::StringPrintf;
@@ -72,7 +71,7 @@
   utsname uts;
   if (uname(&uts) == -1) return;
 
-  std::string fingerprint = property_get("ro.build.fingerprint");
+  std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
   if (fingerprint.empty()) return;
 
   std::string kernel_cmdline;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index c860e40..02e314f 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -45,16 +45,16 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
-#include <fs_mgr.h>
 #include <android-base/file.h>
 #include <android-base/parseint.h>
-#include <android-base/strings.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
-#include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
 #include <ext4_utils/ext4_crypt.h>
 #include <ext4_utils/ext4_crypt_init_extensions.h>
+#include <fs_mgr.h>
 #include <logwrap/logwrap.h>
 
 #include "action.h"
@@ -148,6 +148,12 @@
     return 0;
 }
 
+static int do_class_restart(const std::vector<std::string>& args) {
+    ServiceManager::GetInstance().
+        ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
+    return 0;
+}
+
 static int do_domainname(const std::vector<std::string>& args) {
     return write_file("/proc/sys/kernel/domainname", args[1].c_str()) ? 0 : 1;
 }
@@ -866,8 +872,7 @@
 }
 
 static bool is_file_crypto() {
-    std::string value = property_get("ro.crypto.type");
-    return value == "file";
+    return android::base::GetProperty("ro.crypto.type", "") == "file";
 }
 
 static int do_installkey(const std::vector<std::string>& args) {
@@ -890,6 +895,7 @@
         {"chmod",                   {2,     2,    do_chmod}},
         {"chown",                   {2,     3,    do_chown}},
         {"class_reset",             {1,     1,    do_class_reset}},
+        {"class_restart",           {1,     1,    do_class_restart}},
         {"class_start",             {1,     1,    do_class_start}},
         {"class_stop",              {1,     1,    do_class_stop}},
         {"copy",                    {2,     2,    do_copy}},
diff --git a/init/init.cpp b/init/init.cpp
index 5447007..4249115 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -41,13 +41,10 @@
 #include <selinux/android.h>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <cutils/fs.h>
-#include <cutils/iosched_policy.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
 #include <libavb/libavb.h>
 #include <private/android_filesystem_config.h>
 
@@ -72,6 +69,7 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::GetProperty;
 using android::base::StringPrintf;
 
 struct selabel_handle *sehandle;
@@ -138,7 +136,7 @@
     if (waiting_for_prop) {
         return false;
     }
-    if (property_get(name) != value) {
+    if (GetProperty(name, "") != value) {
         // Current property value is not equal to expected value
         wait_prop_name = name;
         wait_prop_value = value;
@@ -426,7 +424,7 @@
 
 static int console_init_action(const std::vector<std::string>& args)
 {
-    std::string console = property_get("ro.boot.console");
+    std::string console = GetProperty("ro.boot.console", "");
     if (!console.empty()) {
         default_console = "/dev/" + console;
     }
@@ -450,11 +448,11 @@
 }
 
 static void export_oem_lock_status() {
-    if (property_get("ro.oem_unlock_supported") != "1") {
+    if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
         return;
     }
 
-    std::string value = property_get("ro.boot.verifiedbootstate");
+    std::string value = GetProperty("ro.boot.verifiedbootstate", "");
 
     if (!value.empty()) {
         property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
@@ -475,7 +473,7 @@
         { "ro.boot.revision",   "ro.revision",   "0", },
     };
     for (size_t i = 0; i < arraysize(prop_map); i++) {
-        std::string value = property_get(prop_map[i].src_prop);
+        std::string value = GetProperty(prop_map[i].src_prop, "");
         property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
     }
 }
@@ -1252,7 +1250,7 @@
     parser.AddSectionParser("service",std::make_unique<ServiceParser>());
     parser.AddSectionParser("on", std::make_unique<ActionParser>());
     parser.AddSectionParser("import", std::make_unique<ImportParser>());
-    std::string bootscript = property_get("ro.boot.init_rc");
+    std::string bootscript = GetProperty("ro.boot.init_rc", "");
     if (bootscript.empty()) {
         parser.ParseConfig("/init.rc");
         parser.set_is_system_etc_init_loaded(
@@ -1292,7 +1290,7 @@
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
 
     // Don't mount filesystems or start core system services in charger mode.
-    std::string bootmode = property_get("ro.bootmode");
+    std::string bootmode = GetProperty("ro.bootmode", "");
     if (bootmode == "charger") {
         am.QueueEventTrigger("charger");
     } else {
diff --git a/init/init.h b/init/init.h
index 1a05d98..fe850ef 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,9 +19,6 @@
 
 #include <string>
 
-class Action;
-class Service;
-
 extern const char *ENV[32];
 extern std::string default_console;
 extern struct selabel_handle *sehandle;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 3dbb2f0..5801ea8 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -23,9 +23,10 @@
 #include <linux/keychord.h>
 #include <unistd.h>
 
+#include <android-base/properties.h>
+
 #include "init.h"
 #include "log.h"
-#include "property_service.h"
 #include "service.h"
 
 static struct input_keychord *keychords = 0;
@@ -74,7 +75,7 @@
     }
 
     // Only handle keychords if adb is enabled.
-    std::string adb_enabled = property_get("init.svc.adbd");
+    std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
     if (adb_enabled == "running") {
         Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
         if (svc) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 983e684..a4d8b5f 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -30,10 +30,6 @@
 #include <memory>
 #include <vector>
 
-#include <cutils/misc.h>
-#include <cutils/sockets.h>
-#include <cutils/multiuser.h>
-
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -118,12 +114,6 @@
     return check_mac_perms(ctl_name, sctx, cr);
 }
 
-std::string property_get(const char* name) {
-    char value[PROP_VALUE_MAX] = {0};
-    __system_property_get(name, value);
-    return value;
-}
-
 static void write_persistent_property(const char *name, const char *value)
 {
     char tempPath[PATH_MAX];
@@ -592,10 +582,7 @@
 
 static void load_override_properties() {
     if (ALLOW_LOCAL_PROP_OVERRIDE) {
-        std::string debuggable = property_get("ro.debuggable");
-        if (debuggable == "1") {
-            load_properties_from_file("/data/local.prop", NULL);
-        }
+        load_properties_from_file("/data/local.prop", NULL);
     }
 }
 
diff --git a/init/property_service.h b/init/property_service.h
index 5d59473..994da63 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,7 +32,6 @@
 void load_persist_props(void);
 void load_system_props(void);
 void start_property_service(void);
-std::string property_get(const char* name);
 uint32_t property_set(const std::string& name, const std::string& value);
 bool is_legal_property_name(const std::string& name);
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 261a437..2844d78 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -32,17 +32,15 @@
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
-#include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
-#include <cutils/partition_utils.h>
 #include <fs_mgr.h>
 #include <logwrap/logwrap.h>
 
 #include "log.h"
-#include "property_service.h"
 #include "reboot.h"
 #include "service.h"
 #include "util.h"
@@ -342,12 +340,9 @@
         abort();
     }
 
-    std::string timeout = property_get("ro.build.shutdown_timeout");
     /* TODO update default waiting time based on usage data */
-    unsigned int shutdownTimeout = 10;  // default value
-    if (android::base::ParseUint(timeout, &shutdownTimeout)) {
-        LOG(INFO) << "ro.build.shutdown_timeout set:" << shutdownTimeout;
-    }
+    unsigned int shutdownTimeout = android::base::GetUintProperty("ro.build.shutdown_timeout", 10u);
+    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
 
     static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
     for (const char* name : shutdown_critical_services) {
diff --git a/init/service.cpp b/init/service.cpp
index a6efe52..ede6364 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
 
 #include <android-base/file.h>
 #include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <system/thread_defs.h>
@@ -149,27 +150,44 @@
     : name(name), value(value) {
 }
 
-Service::Service(const std::string& name, const std::string& classname,
-                 const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(0), pid_(0),
-      crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
-      seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), oom_score_adjust_(-1000), args_(args) {
+Service::Service(const std::string& name, const std::vector<std::string>& args)
+    : name_(name),
+      classnames_({"default"}),
+      flags_(0),
+      pid_(0),
+      crash_count_(0),
+      uid_(0),
+      gid_(0),
+      namespace_flags_(0),
+      seclabel_(""),
+      ioprio_class_(IoSchedClass_NONE),
+      ioprio_pri_(0),
+      priority_(0),
+      oom_score_adjust_(-1000),
+      args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
-Service::Service(const std::string& name, const std::string& classname,
-                 unsigned flags, uid_t uid, gid_t gid,
-                 const std::vector<gid_t>& supp_gids,
-                 const CapSet& capabilities, unsigned namespace_flags,
-                 const std::string& seclabel,
+Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
+                 const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+                 unsigned namespace_flags, const std::string& seclabel,
                  const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(flags), pid_(0),
-      crash_count_(0), uid_(uid), gid_(gid),
-      supp_gids_(supp_gids), capabilities_(capabilities),
-      namespace_flags_(namespace_flags), seclabel_(seclabel),
-      ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
-      oom_score_adjust_(-1000), args_(args) {
+    : name_(name),
+      classnames_({"default"}),
+      flags_(flags),
+      pid_(0),
+      crash_count_(0),
+      uid_(uid),
+      gid_(gid),
+      supp_gids_(supp_gids),
+      capabilities_(capabilities),
+      namespace_flags_(namespace_flags),
+      seclabel_(seclabel),
+      ioprio_class_(IoSchedClass_NONE),
+      ioprio_pri_(0),
+      priority_(0),
+      oom_score_adjust_(-1000),
+      args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -300,7 +318,7 @@
 
 void Service::DumpState() const {
     LOG(INFO) << "service " << name_;
-    LOG(INFO) << "  class '" << classname_ << "'";
+    LOG(INFO) << "  class '" << android::base::Join(classnames_, " ") << "'";
     LOG(INFO) << "  exec "<< android::base::Join(args_, " ");
     std::for_each(descriptors_.begin(), descriptors_.end(),
                   [] (const auto& info) { LOG(INFO) << *info; });
@@ -337,7 +355,7 @@
 }
 
 bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
-    classname_ = args[1];
+    classnames_ = std::set<std::string>(args.begin() + 1, args.end());
     return true;
 }
 
@@ -519,10 +537,11 @@
 
 Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
+    // clang-format off
     static const Map option_parsers = {
         {"capabilities",
                         {1,     kMax, &Service::ParseCapabilities}},
-        {"class",       {1,     1,    &Service::ParseClass}},
+        {"class",       {1,     kMax, &Service::ParseClass}},
         {"console",     {0,     1,    &Service::ParseConsole}},
         {"critical",    {0,     0,    &Service::ParseCritical}},
         {"disabled",    {0,     0,    &Service::ParseDisabled}},
@@ -542,6 +561,7 @@
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
+    // clang-format on
     return option_parsers;
 }
 
@@ -653,7 +673,7 @@
         if (iter == writepid_files_.end()) {
             // There were no "writepid" instructions for cpusets, check if the system default
             // cpuset is specified to be used for the process.
-            std::string default_cpuset = property_get("ro.cpuset.default");
+            std::string default_cpuset = android::base::GetProperty("ro.cpuset.default", "");
             if (!default_cpuset.empty()) {
                 // Make sure the cpuset name starts and ends with '/'.
                 // A single '/' means the 'root' cpuset.
@@ -933,8 +953,8 @@
         }
     }
 
-    auto svc_p = std::make_unique<Service>(name, "default", flags, uid, gid, supp_gids,
-                                           no_capabilities, namespace_flags, seclabel, str_args);
+    auto svc_p = std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
+                                           namespace_flags, seclabel, str_args);
     Service* svc = svc_p.get();
     services_.emplace_back(std::move(svc_p));
 
@@ -984,7 +1004,7 @@
 void ServiceManager::ForEachServiceInClass(const std::string& classname,
                                            void (*func)(Service* svc)) const {
     for (const auto& s : services_) {
-        if (classname == s->classname()) {
+        if (s->classnames().find(classname) != s->classnames().end()) {
             func(s.get());
         }
     }
@@ -1083,7 +1103,7 @@
     }
 
     std::vector<std::string> str_args(args.begin() + 2, args.end());
-    service_ = std::make_unique<Service>(name, "default", str_args);
+    service_ = std::make_unique<Service>(name, str_args);
     return true;
 }
 
diff --git a/init/service.h b/init/service.h
index 3ca7c32..f08a03f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -22,6 +22,7 @@
 #include <cutils/iosched_policy.h>
 
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -64,12 +65,10 @@
 };
 
 class Service {
-public:
-    Service(const std::string& name, const std::string& classname,
-            const std::vector<std::string>& args);
+  public:
+    Service(const std::string& name, const std::vector<std::string>& args);
 
-    Service(const std::string& name, const std::string& classname,
-            unsigned flags, uid_t uid, gid_t gid,
+    Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
             const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
             unsigned namespace_flags, const std::string& seclabel,
             const std::vector<std::string>& args);
@@ -88,10 +87,10 @@
     void Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
-    bool IsShutdownCritical() { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
+    bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
 
     const std::string& name() const { return name_; }
-    const std::string& classname() const { return classname_; }
+    const std::set<std::string>& classnames() const { return classnames_; }
     unsigned flags() const { return flags_; }
     pid_t pid() const { return pid_; }
     uid_t uid() const { return uid_; }
@@ -104,7 +103,7 @@
     void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
     const std::vector<std::string>& args() const { return args_; }
 
-private:
+  private:
     using OptionParser = bool (Service::*) (const std::vector<std::string>& args,
                                             std::string* err);
     class OptionParserMap;
@@ -140,7 +139,7 @@
     bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
 
     std::string name_;
-    std::string classname_;
+    std::set<std::string> classnames_;
     std::string console_;
 
     unsigned flags_;
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 1041b82..5e3acac 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -24,8 +24,6 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
 
 #include "action.h"
 #include "init.h"
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 915afbd..f27be64 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -26,6 +26,7 @@
 
 #include <sys/types.h>
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <selinux/selinux.h>
 
@@ -34,7 +35,6 @@
 #include "util.h"
 #include "devices.h"
 #include "ueventd_parser.h"
-#include "property_service.h"
 
 int ueventd_main(int argc, char **argv)
 {
@@ -71,7 +71,7 @@
      * TODO: cleanup platform ueventd.rc to remove vendor specific
      * device node entries (b/34968103)
      */
-    std::string hardware = property_get("ro.hardware");
+    std::string hardware = android::base::GetProperty("ro.hardware", "");
     ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
 
     device_init();
diff --git a/init/util.cpp b/init/util.cpp
index 0ba9800..8a19939 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -38,6 +38,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -48,7 +49,6 @@
 
 #include "init.h"
 #include "log.h"
-#include "property_service.h"
 #include "reboot.h"
 #include "util.h"
 
@@ -395,7 +395,7 @@
             return false;
         }
 
-        std::string prop_val = property_get(prop_name.c_str());
+        std::string prop_val = android::base::GetProperty(prop_name, "");
         if (prop_val.empty()) {
             if (def_val.empty()) {
                 LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index e0e6a34..96ca566 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -41,7 +42,7 @@
 }
 
 int load_canned_fs_config(const char* fn) {
-    char line[PATH_MAX + 200];
+    char buf[PATH_MAX + 200];
     FILE* f;
 
     f = fopen(fn, "r");
@@ -50,17 +51,21 @@
         return -1;
     }
 
-    while (fgets(line, sizeof(line), f)) {
+    while (fgets(buf, sizeof(buf), f)) {
         Path* p;
         char* token;
+        char* line = buf;
+        bool rootdir;
 
         while (canned_used >= canned_alloc) {
             canned_alloc = (canned_alloc+1) * 2;
             canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
         }
         p = canned_data + canned_used;
-        p->path = strdup(strtok(line, " "));
-        p->uid = atoi(strtok(NULL, " "));
+        if (line[0] == '/') line++;
+        rootdir = line[0] == ' ';
+        p->path = strdup(rootdir ? "" : strtok(line, " "));
+        p->uid = atoi(strtok(rootdir ? line : NULL, " "));
         p->gid = atoi(strtok(NULL, " "));
         p->mode = strtol(strtok(NULL, " "), NULL, 8);   // mode is in octal
         p->capabilities = 0;
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 40144cf..73ca518 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -51,13 +51,8 @@
 
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
-static int __sys_supports_schedgroups = -1;
 static int __sys_supports_timerslack = -1;
 
-// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
-static int bg_cgroup_fd = -1;
-static int fg_cgroup_fd = -1;
-
 // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
 static int system_bg_cpuset_fd = -1;
 static int bg_cpuset_fd = -1;
@@ -151,23 +146,6 @@
 
 static void __initialize() {
     const char* filename;
-    if (!access("/dev/cpuctl/tasks", W_OK)) {
-        __sys_supports_schedgroups = 1;
-
-        filename = "/dev/cpuctl/tasks";
-        fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        if (fg_cgroup_fd < 0) {
-            SLOGE("open of %s failed: %s\n", filename, strerror(errno));
-        }
-
-        filename = "/dev/cpuctl/bg_non_interactive/tasks";
-        bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        if (bg_cgroup_fd < 0) {
-            SLOGE("open of %s failed: %s\n", filename, strerror(errno));
-        }
-    } else {
-        __sys_supports_schedgroups = 0;
-    }
 
     if (cpusets_enabled()) {
         if (!access("/dev/cpuset/tasks", W_OK)) {
@@ -276,48 +254,26 @@
     }
     pthread_once(&the_once, __initialize);
 
-    if (__sys_supports_schedgroups) {
-        char grpBuf[32];
+    char grpBuf[32];
 
-        if (cpusets_enabled()) {
-            if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
-                return -1;
-            if (grpBuf[0] == '\0') {
-                *policy = SP_FOREGROUND;
-            } else if (!strcmp(grpBuf, "foreground")) {
-                *policy = SP_FOREGROUND;
-            } else if (!strcmp(grpBuf, "background")) {
-                *policy = SP_BACKGROUND;
-            } else if (!strcmp(grpBuf, "top-app")) {
-                *policy = SP_TOP_APP;
-            } else {
-                errno = ERANGE;
-                return -1;
-            }
-        } else {
-            if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
-                return -1;
-            if (grpBuf[0] == '\0') {
-                *policy = SP_FOREGROUND;
-            } else if (!strcmp(grpBuf, "bg_non_interactive")) {
-                *policy = SP_BACKGROUND;
-            } else {
-                errno = ERANGE;
-                return -1;
-            }
-        }
-    } else {
-        int rc = sched_getscheduler(tid);
-        if (rc < 0)
-            return -1;
-        else if (rc == SCHED_NORMAL)
+    if (cpusets_enabled()) {
+        if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0) return -1;
+        if (grpBuf[0] == '\0') {
             *policy = SP_FOREGROUND;
-        else if (rc == SCHED_BATCH)
+        } else if (!strcmp(grpBuf, "foreground")) {
+            *policy = SP_FOREGROUND;
+        } else if (!strcmp(grpBuf, "background")) {
             *policy = SP_BACKGROUND;
-        else {
+        } else if (!strcmp(grpBuf, "top-app")) {
+            *policy = SP_TOP_APP;
+        } else {
             errno = ERANGE;
             return -1;
         }
+    } else {
+        // In b/34193533, we removed bg_non_interactive cgroup, so now
+        // all threads are in FOREGROUND cgroup
+        *policy = SP_FOREGROUND;
     }
     return 0;
 }
@@ -440,49 +396,30 @@
     }
 #endif
 
-    if (__sys_supports_schedgroups) {
-        int fd = -1;
+    if (schedboost_enabled()) {
         int boost_fd = -1;
         switch (policy) {
         case SP_BACKGROUND:
-            fd = bg_cgroup_fd;
             boost_fd = bg_schedboost_fd;
             break;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
-            fd = fg_cgroup_fd;
             boost_fd = fg_schedboost_fd;
             break;
         case SP_TOP_APP:
-            fd = fg_cgroup_fd;
             boost_fd = ta_schedboost_fd;
             break;
         default:
-            fd = -1;
             boost_fd = -1;
             break;
         }
 
-        if (fd > 0 && add_tid_to_cgroup(tid, fd) != 0) {
+        if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
 
-        if (schedboost_enabled()) {
-            if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
-                if (errno != ESRCH && errno != ENOENT)
-                    return -errno;
-            }
-        }
-    } else {
-        struct sched_param param;
-
-        param.sched_priority = 0;
-        sched_setscheduler(tid,
-                           (policy == SP_BACKGROUND) ?
-                           SCHED_BATCH : SCHED_NORMAL,
-                           &param);
     }
 
     if (__sys_supports_timerslack) {
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 2da204a..4dedf7f 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -24,7 +24,6 @@
 #include <stddef.h>
 #include <stdbool.h>
 #include <string.h>
-#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -36,24 +35,12 @@
 #define SYS_POWER_STATE "/sys/power/state"
 #define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
 
-#define BASE_SLEEP_TIME 100000
-
 static int state_fd;
 static int wakeup_count_fd;
 static pthread_t suspend_thread;
 static sem_t suspend_lockout;
 static const char *sleep_state = "mem";
 static void (*wakeup_func)(bool success) = NULL;
-static int sleep_time = BASE_SLEEP_TIME;
-
-static void update_sleep_time(bool success) {
-    if (success) {
-        sleep_time = BASE_SLEEP_TIME;
-        return;
-    }
-    // double sleep time after each failure up to one minute
-    sleep_time = MIN(sleep_time * 2, 60000000);
-}
 
 static void *suspend_thread_func(void *arg __attribute__((unused)))
 {
@@ -61,12 +48,10 @@
     char wakeup_count[20];
     int wakeup_count_len;
     int ret;
-    bool success = true;
+    bool success;
 
     while (1) {
-        update_sleep_time(success);
-        usleep(sleep_time);
-        success = false;
+        usleep(100000);
         ALOGV("%s: read wakeup_count\n", __func__);
         lseek(wakeup_count_fd, 0, SEEK_SET);
         wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
@@ -90,6 +75,7 @@
             continue;
         }
 
+        success = true;
         ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
         ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
         if (ret < 0) {
@@ -98,8 +84,8 @@
         } else {
             ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
             ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
-            if (ret >= 0) {
-                success = true;
+            if (ret < 0) {
+                success = false;
             }
             void (*func)(bool success) = wakeup_func;
             if (func != NULL) {
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 81356fe..04a620c 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -235,7 +235,9 @@
     }
     iovec[1].iov_len = entry.len;
 
-    log_time retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mRealTime;
+    log_time retval = reader->sendDatav(iovec, 1 + (entry.len != 0))
+                          ? FLUSH_ERROR
+                          : mRealTime;
 
     if (buffer) free(buffer);
 
diff --git a/qemu_pipe/Android.mk b/qemu_pipe/Android.mk
deleted file mode 100644
index 6e0144c..0000000
--- a/qemu_pipe/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-common_static_libraries := \
-    libbase
-include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-LOCAL_SRC_FILES:= \
-    qemu_pipe.cpp
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/include \
-    system/base/include
-LOCAL_MODULE:= libqemu_pipe
-LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-include $(BUILD_STATIC_LIBRARY)
diff --git a/qemu_pipe/include/qemu_pipe.h b/qemu_pipe/include/qemu_pipe.h
deleted file mode 100644
index 0987498..0000000
--- a/qemu_pipe/include/qemu_pipe.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 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_CORE_INCLUDE_QEMU_PIPE_H
-#define ANDROID_CORE_INCLUDE_QEMU_PIPE_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-// Try to open a new Qemu fast-pipe. This function returns a file descriptor
-// that can be used to communicate with a named service managed by the
-// emulator.
-//
-// This file descriptor can be used as a standard pipe/socket descriptor.
-//
-// 'pipeName' is the name of the emulator service you want to connect to,
-// and should begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
-// For backward compatibility, the 'pipe:' prefix can be omitted, and in
-// that case, qemu_pipe_open will add it for you.
-
-// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
-//
-// EINVAL  -> unknown/unsupported pipeName
-// ENOSYS  -> fast pipes not available in this system.
-//
-// ENOSYS should never happen, except if you're trying to run within a
-// misconfigured emulator.
-//
-// You should be able to open several pipes to the same pipe service,
-// except for a few special cases (e.g. GSM modem), where EBUSY will be
-// returned if more than one client tries to connect to it.
-int qemu_pipe_open(const char* pipeName);
-
-// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
-// This really adds a 4-hexchar prefix describing the payload size.
-// Returns 0 on success, and -1 on error.
-int qemu_pipe_frame_send(int fd, const void* buff, size_t len);
-
-// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
-// If the framed message is larger than |len|, then this returns -1 and the
-// content is lost. Otherwise, this returns the size of the message. NOTE:
-// empty messages are possible in a framed wire protocol and do not mean
-// end-of-stream.
-int qemu_pipe_frame_recv(int fd, void* buff, size_t len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_CORE_INCLUDE_QEMU_PIPE_H */
diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp
deleted file mode 100644
index beeccb0..0000000
--- a/qemu_pipe/qemu_pipe.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2011 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 "qemu_pipe.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include <android-base/file.h>
-
-using android::base::ReadFully;
-using android::base::WriteFully;
-
-// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
-// occurs during pipe operations. The macro should simply take a printf-style
-// formatting string followed by optional arguments.
-#ifndef QEMU_PIPE_DEBUG
-#  define  QEMU_PIPE_DEBUG(...)   (void)0
-#endif
-
-int qemu_pipe_open(const char* pipeName) {
-    // Sanity check.
-    if (!pipeName) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
-    if (fd < 0) {
-        QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
-                        strerror(errno));
-        return -1;
-    }
-
-    // Write the pipe name, *including* the trailing zero which is necessary.
-    size_t pipeNameLen = strlen(pipeName);
-    if (WriteFully(fd, pipeName, pipeNameLen + 1U)) {
-        return fd;
-    }
-
-    // now, add 'pipe:' prefix and try again
-    // Note: host side will wait for the trailing '\0' to start
-    // service lookup.
-    const char pipe_prefix[] = "pipe:";
-    if (WriteFully(fd, pipe_prefix, strlen(pipe_prefix)) &&
-            WriteFully(fd, pipeName, pipeNameLen + 1U)) {
-        return fd;
-    }
-    QEMU_PIPE_DEBUG("%s: Could not write to %s pipe service: %s",
-            __FUNCTION__, pipeName, strerror(errno));
-    close(fd);
-    return -1;
-}
-
-int qemu_pipe_frame_send(int fd, const void* buff, size_t len) {
-    char header[5];
-    snprintf(header, sizeof(header), "%04zx", len);
-    if (!WriteFully(fd, header, 4)) {
-        QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
-        return -1;
-    }
-    if (!WriteFully(fd, buff, len)) {
-        QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
-        return -1;
-    }
-    return 0;
-}
-
-int qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
-    char header[5];
-    if (!ReadFully(fd, header, 4)) {
-        QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
-        return -1;
-    }
-    header[4] = '\0';
-    size_t size;
-    if (sscanf(header, "%04zx", &size) != 1) {
-        QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
-        return -1;
-    }
-    if (size > len) {
-        QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
-                        len);
-        return -1;
-    }
-    if (!ReadFully(fd, buff, size)) {
-        QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
-                        strerror(errno));
-        return -1;
-    }
-    return size;
-}
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 381df5a..8fcd17f 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,6 +30,19 @@
 
 #include "android-base/logging.h"
 
+// The name of the directory that holds a staged time zone update distro. If this exists it should
+// replace the one in CURRENT_DIR_NAME.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* STAGED_DIR_NAME = "/staged";
+
+// The name of the directory that holds the (optional) installed time zone update distro.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* CURRENT_DIR_NAME = "/current";
+
+// The name of a file in the staged dir that indicates the staged operation is an "uninstall".
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
+
 // The name of the file containing the distro version information.
 // See also libcore.tzdata.shared2.TimeZoneDistro / libcore.tzdata.shared2.DistroVersion.
 static const char* DISTRO_VERSION_FILENAME = "/distro_version";
@@ -75,7 +88,6 @@
 static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
 static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
 
-
 static void usage() {
     std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
             "\n"
@@ -184,7 +196,7 @@
     return 0;
 }
 
-enum PathStatus { ERR, NONE, IS_DIR, NOT_DIR };
+enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
 
 static PathStatus checkPath(const std::string& path) {
     struct stat buf;
@@ -195,7 +207,31 @@
         }
         return NONE;
     }
-    return S_ISDIR(buf.st_mode) ? IS_DIR : NOT_DIR;
+    return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
+}
+
+/*
+ * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
+ * cannot be accessed this method returns false.
+ */
+static bool deleteFile(const std::string& fileToDelete) {
+    // Check whether the file exists.
+    PathStatus pathStatus = checkPath(fileToDelete);
+    if (pathStatus == NONE) {
+        LOG(INFO) << "Path " << fileToDelete << " does not exist";
+        return true;
+    }
+    if (pathStatus != IS_REG) {
+        LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
+        return false;
+    }
+
+    // Attempt the deletion.
+    int rc = unlink(fileToDelete.c_str());
+    if (rc != 0) {
+        PLOG(WARNING) << "unlink() failed for " << fileToDelete;
+    }
+    return rc == 0;
 }
 
 /*
@@ -260,8 +296,7 @@
     std::string dataUpdatesDirName(dataZoneInfoDir);
     dataUpdatesDirName += "/updates";
     LOG(INFO) << "Removing: " << dataUpdatesDirName;
-    bool deleted = deleteDir(dataUpdatesDirName);
-    if (!deleted) {
+    if (!deleteDir(dataUpdatesDirName)) {
         LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
                 << " was not successful";
     }
@@ -270,14 +305,151 @@
 /*
  * Deletes the timezone update distro directory.
  */
-static void deleteUpdateDistroDir(std::string& distroDirName) {
+static void deleteUpdateDistroDir(const std::string& distroDirName) {
     LOG(INFO) << "Removing: " << distroDirName;
-    bool deleted = deleteDir(distroDirName);
-    if (!deleted) {
+    if (!deleteDir(distroDirName)) {
         LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
     }
 }
 
+static void handleStagedUninstall(const std::string& dataStagedDirName,
+                                  const std::string& dataCurrentDirName,
+                                  const PathStatus dataCurrentDirStatus) {
+    LOG(INFO) << "Staged operation is an uninstall.";
+
+    // Delete the current install directory.
+    switch (dataCurrentDirStatus) {
+        case NONE:
+            // This is unexpected: No uninstall should be staged if there is nothing to
+            // uninstall. Carry on anyway.
+            LOG(WARNING) << "No current install to delete.";
+            break;
+        case IS_DIR:
+            // This is normal. Delete the current install dir.
+            if (!deleteDir(dataCurrentDirName)) {
+                LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+                             << " was not successful";
+                // If this happens we don't know whether we were able to delete or not. We don't
+                // delete the staged operation so it will be retried next boot unless overridden.
+                return;
+            }
+            break;
+        case IS_REG:
+        default:
+            // This is unexpected: We can try to delete the unexpected file and carry on.
+            LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+                         << " is not actually a directory. Attempting deletion.";
+            if (!deleteFile(dataCurrentDirName)) {
+                LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+                return;
+            }
+            break;
+    }
+
+    // Delete the staged uninstall dir.
+    if (!deleteDir(dataStagedDirName)) {
+        LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+                     << " was not successful";
+        // If this happens we don't know whether we were able to delete the staged operation
+        // or not.
+        return;
+    }
+    LOG(INFO) << "Staged uninstall complete.";
+}
+
+static void handleStagedInstall(const std::string& dataStagedDirName,
+                                const std::string& dataCurrentDirName,
+                                const PathStatus dataCurrentDirStatus) {
+    LOG(INFO) << "Staged operation is an install.";
+
+    switch (dataCurrentDirStatus) {
+        case NONE:
+            // This is expected: This is the first install.
+            LOG(INFO) << "No current install to replace.";
+            break;
+        case IS_DIR:
+            // This is expected: We are replacing an existing install.
+            // Delete the current dir so we can replace it.
+            if (!deleteDir(dataCurrentDirName)) {
+                LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+                             << " was not successful";
+                // If this happens, we cannot proceed.
+                return;
+            }
+            break;
+        case IS_REG:
+        default:
+            // This is unexpected: We can try to delete the unexpected file and carry on.
+            LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+                         << " is not actually a directory. Attempting deletion.";
+            if (!deleteFile(dataCurrentDirName)) {
+                LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+                return;
+            }
+            break;
+    }
+
+    // Move the staged dir so it is the new current dir, completing the install.
+    LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
+    int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
+    if (rc == -1) {
+        PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
+                      << &dataCurrentDirName[0];
+        return;
+    }
+
+    LOG(INFO) << "Staged install complete.";
+}
+/*
+ * Process a staged operation if there is one.
+ */
+static void processStagedOperation(const std::string& dataStagedDirName,
+                                   const std::string& dataCurrentDirName) {
+    PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
+
+    // Exit early for the common case.
+    if (dataStagedDirStatus == NONE) {
+        LOG(DEBUG) << "No staged time zone operation.";
+        return;
+    }
+
+    // Check known directory names are in a good starting state.
+    if (dataStagedDirStatus != IS_DIR) {
+        LOG(WARNING) << "Staged distro dir " << dataStagedDirName
+                     << " could not be accessed or is not a directory."
+                     << " stagedDirStatus=" << dataStagedDirStatus;
+        return;
+    }
+
+    // dataStagedDirStatus == IS_DIR.
+
+    // Work out whether there is anything currently installed.
+    PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
+    if (dataCurrentDirStatus == ERR) {
+        LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
+                     << " dataCurrentDirStatus=" << dataCurrentDirStatus;
+        return;
+    }
+
+    // We must perform the staged operation.
+
+    // Check to see if the staged directory contains an uninstall or an install operation.
+    std::string uninstallTombStoneFile(dataStagedDirName);
+    uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
+    int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
+    if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
+        // Error case.
+        LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
+        return;
+    }
+    if (uninstallTombStoneFileStatus == IS_REG) {
+        handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+    } else {
+        // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
+        handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+    }
+}
+
 /*
  * After a platform update it is likely that timezone data found on the system partition will be
  * newer than the version found in the data partition. This tool detects this case and removes the
@@ -300,15 +472,25 @@
     const char* systemZoneInfoDir = argv[1];
     const char* dataZoneInfoDir = argv[2];
 
-    // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+    std::string dataStagedDirName(dataZoneInfoDir);
+    dataStagedDirName += STAGED_DIR_NAME;
+
     std::string dataCurrentDirName(dataZoneInfoDir);
-    dataCurrentDirName += "/current";
-    int dataCurrentDirStatus = checkPath(dataCurrentDirName);
+    dataCurrentDirName += CURRENT_DIR_NAME;
+
+    // Check for an process any staged operation.
+    // If the staged operation could not be handled we still have to validate the current installed
+    // directory so we do not check for errors and do not quit early.
+    processStagedOperation(dataStagedDirName, dataCurrentDirName);
+
+    // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+    PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
     if (dataCurrentDirStatus == NONE) {
         LOG(INFO) << "timezone distro dir " << dataCurrentDirName
                 << " does not exist. No action required.";
         return 0;
     }
+
     // If the distro directory path is not a directory or we can't stat() the path, exit with a
     // warning: either there's a problem accessing storage or the world is not as it should be;
     // nothing to do.