Merge "libziparchive: Add ability to backup in ZipWriter"
diff --git a/base/file.cpp b/base/file.cpp
index 378a405..d4e5894 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -49,6 +49,14 @@
 bool ReadFdToString(int fd, std::string* content) {
   content->clear();
 
+  // Although original we had small files in mind, this code gets used for
+  // very large files too, where the std::string growth heuristics might not
+  // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
+  struct stat sb;
+  if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
+    content->reserve(sb.st_size);
+  }
+
   char buf[BUFSIZ];
   ssize_t n;
   while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 266131e..02b431d 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -214,3 +214,46 @@
   EXPECT_EQ(".", android::base::Dirname("sh"));
   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
 }
+
+TEST(file, ReadFileToString_capacity) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  // For a huge file, the overhead should still be small.
+  std::string s;
+  size_t size = 16 * 1024 * 1024;
+  ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
+  EXPECT_EQ(size, s.size());
+  EXPECT_LT(s.capacity(), size + 16);
+
+  // Even for weird badly-aligned sizes.
+  size += 12345;
+  ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
+  EXPECT_EQ(size, s.size());
+  EXPECT_LT(s.capacity(), size + 16);
+
+  // We'll shrink an enormous string if you read a small file into it.
+  size = 64;
+  ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
+  EXPECT_EQ(size, s.size());
+  EXPECT_LT(s.capacity(), size + 16);
+}
+
+TEST(file, ReadFileToString_capacity_0) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  // Because /proc reports its files as zero-length, we don't actually trust
+  // any file that claims to be zero-length. Rather than add increasingly
+  // complex heuristics for shrinking the passed-in string in that case, we
+  // currently leave it alone.
+  std::string s;
+  size_t initial_capacity = s.capacity();
+  ASSERT_TRUE(android::base::WriteStringToFile("", tf.path));
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
+  EXPECT_EQ(0U, s.size());
+  EXPECT_EQ(initial_capacity, s.capacity());
+}
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 5ee07cd..325210d 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -77,7 +77,9 @@
     resetLogs();
     elf_set_fake_build_id("");
     siginfo_t si;
+    memset(&si, 0, sizeof(si));
     si.si_signo = SIGABRT;
+    si.si_code = SI_KERNEL;
     ptrace_set_fake_getsiginfo(si);
   }
 
@@ -292,7 +294,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
   si.si_addr = reinterpret_cast<void*>(0x1000);
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -348,7 +352,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
   si.si_addr = reinterpret_cast<void*>(0xa533000);
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -404,7 +410,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
   si.si_addr = reinterpret_cast<void*>(0xa534040);
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -458,7 +466,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
 #if defined(__LP64__)
   si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
 #else
@@ -503,7 +513,7 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
-  si.si_signo = 0;
+  memset(&si, 0, sizeof(si));
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
 
@@ -539,7 +549,9 @@
     ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
 
     siginfo_t si;
+    memset(&si, 0, sizeof(si));
     si.si_signo = i;
+    si.si_code = SI_KERNEL;
     si.si_addr = reinterpret_cast<void*>(0x1000);
     ptrace_set_fake_getsiginfo(si);
     dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -592,7 +604,7 @@
 
 TEST_F(TombstoneTest, dump_signal_info_error) {
   siginfo_t si;
-  si.si_signo = 0;
+  memset(&si, 0, sizeof(si));
   ptrace_set_fake_getsiginfo(si);
 
   dump_signal_info(&log_, 123);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index c23da44..0c38449 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -283,7 +283,7 @@
     if (BacktraceMap::IsValid(map) && !map.name.empty()) {
       line += "  " + map.name;
       uintptr_t offset = 0;
-      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
+      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset, &map));
       if (!func_name.empty()) {
         line += " (" + func_name;
         if (offset) {
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index f3bba7b..a536b22 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -35,10 +35,11 @@
                   return -1;
                 }
                 got_suffix = 1;
+                // remove below line when bootloaders fix androidboot.slot_suffix param
+                if (suffix[0] == '_') suffix.erase(suffix.begin());
             }
 
-            if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device,
-                         suffix.c_str()) > 0) {
+            if (asprintf(&tmp, "%s_%s", fstab->recs[n].blk_device, suffix.c_str()) > 0) {
                 free(fstab->recs[n].blk_device);
                 fstab->recs[n].blk_device = tmp;
             } else {
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index d28ba41..523e1f1 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -77,6 +77,10 @@
     return healthd_get_property(id, val);
 }
 
+void BatteryPropertiesRegistrar::scheduleUpdate() {
+    healthd_battery_update();
+}
+
 status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
     IPCThreadState* self = IPCThreadState::self();
     const int pid = self->getCallingPid();
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index 095f3d3..14e9145 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -32,6 +32,7 @@
 public:
     void publish(const sp<BatteryPropertiesRegistrar>& service);
     void notifyListeners(const struct BatteryProperties& props);
+    void scheduleUpdate();
 
 private:
     Mutex mRegistrationLock;
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index c896ab8..4f73a65 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -104,8 +104,10 @@
   virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
 
   // Get the function name and offset into the function given the pc.
-  // If the string is empty, then no valid function name was found.
-  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
+  // If the string is empty, then no valid function name was found,
+  // or the pc is not in any valid map.
+  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset,
+                                      const backtrace_map_t* map = NULL);
 
   // Fill in the map data associated with the given pc.
   virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index df48dfe..8ab0dfa 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -33,6 +33,10 @@
 #include <string>
 #include <vector>
 
+// Special flag to indicate a map is in /dev/. However, a map in
+// /dev/ashmem/... does not set this flag.
+static constexpr int PROT_DEVICE_MAP = 0x8000;
+
 struct backtrace_map_t {
   uintptr_t start = 0;
   uintptr_t end = 0;
diff --git a/init/Android.mk b/init/Android.mk
index d48f152..c82a19e 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -77,6 +77,7 @@
     init.cpp \
     keychords.cpp \
     property_service.cpp \
+    reboot.cpp \
     signal_handler.cpp \
     ueventd.cpp \
     ueventd_parser.cpp \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 43eb378..24875d5 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -64,6 +64,7 @@
 #include "init_parser.h"
 #include "log.h"
 #include "property_service.h"
+#include "reboot.h"
 #include "service.h"
 #include "signal_handler.h"
 #include "util.h"
@@ -71,7 +72,6 @@
 using namespace std::literals::string_literals;
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
-#define UNMOUNT_CHECK_TIMES 10
 
 static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
 
@@ -116,114 +116,14 @@
     return ret;
 }
 
-// Turn off backlight while we are performing power down cleanup activities.
-static void turnOffBacklight() {
-    static const char off[] = "0";
-
-    android::base::WriteStringToFile(off, "/sys/class/leds/lcd-backlight/brightness");
-
-    static const char backlightDir[] = "/sys/class/backlight";
-    std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(backlightDir), closedir);
-    if (!dir) {
-        return;
-    }
-
-    struct dirent *dp;
-    while ((dp = readdir(dir.get())) != NULL) {
-        if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) ||
-                (dp->d_name[0] == '.')) {
-            continue;
-        }
-
-        std::string fileName = android::base::StringPrintf("%s/%s/brightness",
-                                                           backlightDir,
-                                                           dp->d_name);
-        android::base::WriteStringToFile(off, fileName);
-    }
-}
-
 static int reboot_into_recovery(const std::vector<std::string>& options) {
     std::string err;
     if (!write_bootloader_message(options, &err)) {
         LOG(ERROR) << "failed to set bootloader message: " << err;
         return -1;
     }
-    reboot("recovery");
-}
-
-static void unmount_and_fsck(const struct mntent *entry) {
-    if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
-        return;
-
-    /* First, lazily unmount the directory. This unmount request finishes when
-     * all processes that open a file or directory in |entry->mnt_dir| exit.
-     */
-    TEMP_FAILURE_RETRY(umount2(entry->mnt_dir, MNT_DETACH));
-
-    /* Next, kill all processes except init, kthreadd, and kthreadd's
-     * children to finish the lazy unmount. Killing all processes here is okay
-     * because this callback function is only called right before reboot().
-     * It might be cleaner to selectively kill processes that actually use
-     * |entry->mnt_dir| rather than killing all, probably by reusing a function
-     * like killProcessesWithOpenFiles() in vold/, but the selinux policy does
-     * not allow init to scan /proc/<pid> files which the utility function
-     * heavily relies on. The policy does not allow the process to execute
-     * killall/pkill binaries either. Note that some processes might
-     * automatically restart after kill(), but that is not really a problem
-     * because |entry->mnt_dir| is no longer visible to such new processes.
-     */
-    ServiceManager::GetInstance().ForEachService([] (Service* s) { s->Stop(); });
-    TEMP_FAILURE_RETRY(kill(-1, SIGKILL));
-
-    // Restart Watchdogd to allow us to complete umounting and fsck
-    Service *svc = ServiceManager::GetInstance().FindServiceByName("watchdogd");
-    if (svc) {
-        do {
-            sched_yield(); // do not be so eager, let cleanup have priority
-            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
-        } while (svc->flags() & SVC_RUNNING); // Paranoid Cargo
-        svc->Start();
-    }
-
-    turnOffBacklight();
-
-    int count = 0;
-    while (count++ < UNMOUNT_CHECK_TIMES) {
-        int fd = TEMP_FAILURE_RETRY(open(entry->mnt_fsname, O_RDONLY | O_EXCL));
-        if (fd >= 0) {
-            /* |entry->mnt_dir| has sucessfully been unmounted. */
-            close(fd);
-            break;
-        } else if (errno == EBUSY) {
-            // Some processes using |entry->mnt_dir| are still alive. Wait for a
-            // while then retry.
-            std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
-            continue;
-        } else {
-            /* Cannot open the device. Give up. */
-            return;
-        }
-    }
-
-    // NB: With watchdog still running, there is no cap on the time it takes
-    // to complete the fsck, from the users perspective the device graphics
-    // and responses are locked-up and they may choose to hold the power
-    // button in frustration if it drags out.
-
-    int st;
-    if (!strcmp(entry->mnt_type, "f2fs")) {
-        const char *f2fs_argv[] = {
-            "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
-        };
-        android_fork_execvp_ext(arraysize(f2fs_argv), (char **)f2fs_argv,
-                                &st, true, LOG_KLOG, true, NULL, NULL, 0);
-    } else if (!strcmp(entry->mnt_type, "ext4")) {
-        const char *ext4_argv[] = {
-            "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
-        };
-        android_fork_execvp_ext(arraysize(ext4_argv), (char **)ext4_argv,
-                                &st, true, LOG_KLOG, true, NULL, NULL, 0);
-    }
+    DoReboot(ANDROID_RB_RESTART2, "reboot", "recovery", false);
+    return 0;
 }
 
 static int do_class_start(const std::vector<std::string>& args) {
@@ -706,86 +606,51 @@
 }
 
 static int do_powerctl(const std::vector<std::string>& args) {
-    const char* command = args[1].c_str();
-    int len = 0;
+    const std::string& command = args[1];
     unsigned int cmd = 0;
-    const char *reboot_target = "";
-    void (*callback_on_ro_remount)(const struct mntent*) = NULL;
+    std::vector<std::string> cmd_params = android::base::Split(command, ",");
+    std::string reason_string = cmd_params[0];
+    std::string reboot_target = "";
+    bool runFsck = false;
+    bool commandInvalid = false;
 
-    if (strncmp(command, "shutdown", 8) == 0) {
+    if (cmd_params.size() > 2) {
+        commandInvalid = true;
+    } else if (cmd_params[0] == "shutdown") {
         cmd = ANDROID_RB_POWEROFF;
-        len = 8;
-    } else if (strncmp(command, "reboot", 6) == 0) {
+        if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
+            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
+            // Run fsck once the file system is remounted in read-only mode.
+            runFsck = true;
+            reason_string = cmd_params[1];
+        }
+    } else if (cmd_params[0] == "reboot") {
         cmd = ANDROID_RB_RESTART2;
-        len = 6;
-    } else if (strncmp(command, "thermal-shutdown", 16) == 0) {
+        if (cmd_params.size() == 2) {
+            reboot_target = cmd_params[1];
+            // When rebooting to the bootloader notify the bootloader writing
+            // also the BCB.
+            if (reboot_target == "bootloader") {
+                std::string err;
+                if (!write_reboot_bootloader(&err)) {
+                    LOG(ERROR) << "reboot-bootloader: Error writing "
+                                  "bootloader_message: "
+                               << err;
+                }
+            }
+        }
+    } else if (command == "thermal-shutdown") {  // no additional parameter allowed
         cmd = ANDROID_RB_THERMOFF;
-        len = 16;
     } else {
+        commandInvalid = true;
+    }
+    if (commandInvalid) {
         LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
         return -EINVAL;
     }
 
-    if (command[len] == ',') {
-        if (cmd == ANDROID_RB_POWEROFF &&
-            !strcmp(&command[len + 1], "userrequested")) {
-            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
-            // Run fsck once the file system is remounted in read-only mode.
-            callback_on_ro_remount = unmount_and_fsck;
-        } else if (cmd == ANDROID_RB_RESTART2) {
-            reboot_target = &command[len + 1];
-            // When rebooting to the bootloader notify the bootloader writing
-            // also the BCB.
-            if (strcmp(reboot_target, "bootloader") == 0) {
-                std::string err;
-                if (!write_reboot_bootloader(&err)) {
-                    LOG(ERROR) << "reboot-bootloader: Error writing "
-                                  "bootloader_message: " << err;
-                }
-            }
-        }
-    } else if (command[len] != '\0') {
-        LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
-        return -EINVAL;
-    }
-
-    std::string timeout = property_get("ro.build.shutdown_timeout");
-    unsigned int delay = 0;
-
-    if (android::base::ParseUint(timeout, &delay) && delay > 0) {
-        Timer t;
-        // Ask all services to terminate.
-        ServiceManager::GetInstance().ForEachService(
-            [] (Service* s) { s->Terminate(); });
-
-        while (t.duration_s() < delay) {
-            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
-
-            int service_count = 0;
-            ServiceManager::GetInstance().ForEachService(
-                [&service_count] (Service* s) {
-                    // Count the number of services running.
-                    // Exclude the console as it will ignore the SIGTERM signal
-                    // and not exit.
-                    // Note: SVC_CONSOLE actually means "requires console" but
-                    // it is only used by the shell.
-                    if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
-                        service_count++;
-                    }
-                });
-
-            if (service_count == 0) {
-                // All terminable services terminated. We can exit early.
-                break;
-            }
-
-            // Wait a bit before recounting the number or running services.
-            std::this_thread::sleep_for(50ms);
-        }
-        LOG(VERBOSE) << "Terminating running services took " << t;
-    }
-
-    return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount);
+    DoReboot(cmd, reason_string, reboot_target, runFsck);
+    return 0;
 }
 
 static int do_trigger(const std::vector<std::string>& args) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
new file mode 100644
index 0000000..3e2d61e
--- /dev/null
+++ b/init/reboot.cpp
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 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 <dirent.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <sys/cdefs.h>
+#include <sys/mount.h>
+#include <sys/quota.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/parseint.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"
+
+using android::base::StringPrintf;
+
+// represents umount status during reboot / shutdown.
+enum UmountStat {
+    /* umount succeeded. */
+    UMOUNT_STAT_SUCCESS = 0,
+    /* umount was not run. */
+    UMOUNT_STAT_SKIPPED = 1,
+    /* umount failed with timeout. */
+    UMOUNT_STAT_TIMEOUT = 2,
+    /* could not run due to error */
+    UMOUNT_STAT_ERROR = 3,
+    /* not used by init but reserved for other part to use this to represent the
+       the state where umount status before reboot is not found / available. */
+    UMOUNT_STAT_NOT_AVAILABLE = 4,
+};
+
+// Utility for struct mntent
+class MountEntry {
+  public:
+    explicit MountEntry(const mntent& entry, bool isMounted = true)
+        : mnt_fsname_(entry.mnt_fsname),
+          mnt_dir_(entry.mnt_dir),
+          mnt_type_(entry.mnt_type),
+          is_mounted_(isMounted) {}
+
+    bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
+
+    bool IsExt4() const { return mnt_type_ == "ext4"; }
+
+    bool is_mounted() const { return is_mounted_; }
+
+    void set_is_mounted() { is_mounted_ = false; }
+
+    const std::string& mnt_fsname() const { return mnt_fsname_; }
+
+    const std::string& mnt_dir() const { return mnt_dir_; }
+
+    static bool IsBlockDevice(const struct mntent& mntent) {
+        return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
+    }
+
+    static bool IsEmulatedDevice(const struct mntent& mntent) {
+        static const std::string SDCARDFS_NAME = "sdcardfs";
+        return android::base::StartsWith(mntent.mnt_fsname, "/data/") &&
+               SDCARDFS_NAME == mntent.mnt_type;
+    }
+
+  private:
+    std::string mnt_fsname_;
+    std::string mnt_dir_;
+    std::string mnt_type_;
+    bool is_mounted_;
+};
+
+// Turn off backlight while we are performing power down cleanup activities.
+static void TurnOffBacklight() {
+    static constexpr char OFF[] = "0";
+
+    android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
+
+    static const char backlightDir[] = "/sys/class/backlight";
+    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
+    if (!dir) {
+        return;
+    }
+
+    struct dirent* dp;
+    while ((dp = readdir(dir.get())) != nullptr) {
+        if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
+            continue;
+        }
+
+        std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
+        android::base::WriteStringToFile(OFF, fileName);
+    }
+}
+
+static void DoFsck(const MountEntry& entry) {
+    static constexpr int UNMOUNT_CHECK_TIMES = 10;
+
+    if (!entry.IsF2Fs() && !entry.IsExt4()) return;
+
+    int count = 0;
+    while (count++ < UNMOUNT_CHECK_TIMES) {
+        int fd = TEMP_FAILURE_RETRY(open(entry.mnt_fsname().c_str(), O_RDONLY | O_EXCL));
+        if (fd >= 0) {
+            /* |entry->mnt_dir| has sucessfully been unmounted. */
+            close(fd);
+            break;
+        } else if (errno == EBUSY) {
+            // Some processes using |entry->mnt_dir| are still alive. Wait for a
+            // while then retry.
+            std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
+            continue;
+        } else {
+            /* Cannot open the device. Give up. */
+            return;
+        }
+    }
+
+    // NB: With watchdog still running, there is no cap on the time it takes
+    // to complete the fsck, from the users perspective the device graphics
+    // and responses are locked-up and they may choose to hold the power
+    // button in frustration if it drags out.
+
+    int st;
+    if (entry.IsF2Fs()) {
+        const char* f2fs_argv[] = {
+            "/system/bin/fsck.f2fs", "-f", entry.mnt_fsname().c_str(),
+        };
+        android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG, true,
+                                nullptr, nullptr, 0);
+    } else if (entry.IsExt4()) {
+        const char* ext4_argv[] = {
+            "/system/bin/e2fsck", "-f", "-y", entry.mnt_fsname().c_str(),
+        };
+        android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG, true,
+                                nullptr, nullptr, 0);
+    }
+}
+
+static void ShutdownVold() {
+    const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
+    int status;
+    android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true, LOG_KLOG, true,
+                            nullptr, nullptr, 0);
+}
+
+static void LogShutdownTime(UmountStat stat, Timer* t) {
+    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
+}
+
+static void __attribute__((noreturn))
+RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+    switch (cmd) {
+        case ANDROID_RB_POWEROFF:
+            reboot(RB_POWER_OFF);
+            break;
+
+        case ANDROID_RB_RESTART2:
+            syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                    LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
+            break;
+
+        case ANDROID_RB_THERMOFF:
+            reboot(RB_POWER_OFF);
+            break;
+    }
+    // In normal case, reboot should not return.
+    PLOG(FATAL) << "reboot call returned";
+    abort();
+}
+
+/* Find all read+write block devices and emulated devices in /proc/mounts
+ * and add them to correpsponding list.
+ */
+static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
+                                   std::vector<MountEntry>* emulatedPartitions) {
+    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
+    if (fp == nullptr) {
+        PLOG(ERROR) << "Failed to open /proc/mounts";
+        return false;
+    }
+    mntent* mentry;
+    while ((mentry = getmntent(fp.get())) != nullptr) {
+        if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
+            blockDevPartitions->emplace_back(*mentry);
+        } else if (MountEntry::IsEmulatedDevice(*mentry)) {
+            emulatedPartitions->emplace_back(*mentry);
+        }
+    }
+    return true;
+}
+
+static bool UmountPartitions(std::vector<MountEntry>* partitions, int maxRetry, int flags) {
+    static constexpr int SLEEP_AFTER_RETRY_US = 100000;
+
+    bool umountDone;
+    int retryCounter = 0;
+
+    while (true) {
+        umountDone = true;
+        for (auto& entry : *partitions) {
+            if (entry.is_mounted()) {
+                int r = umount2(entry.mnt_dir().c_str(), flags);
+                if (r == 0) {
+                    entry.set_is_mounted();
+                    LOG(INFO) << StringPrintf("umounted %s, flags:0x%x", entry.mnt_fsname().c_str(),
+                                              flags);
+                } else {
+                    umountDone = false;
+                    PLOG(WARNING) << StringPrintf("cannot umount %s, flags:0x%x",
+                                                  entry.mnt_fsname().c_str(), flags);
+                }
+            }
+        }
+        if (umountDone) break;
+        retryCounter++;
+        if (retryCounter >= maxRetry) break;
+        usleep(SLEEP_AFTER_RETRY_US);
+    }
+    return umountDone;
+}
+
+/* Try umounting all emulated file systems R/W block device cfile systems.
+ * This will just try umount and give it up if it fails.
+ * For fs like ext4, this is ok as file system will be marked as unclean shutdown
+ * and necessary check can be done at the next reboot.
+ * For safer shutdown, caller needs to make sure that
+ * all processes / emulated partition for the target fs are all cleaned-up.
+ *
+ * return true when umount was successful. false when timed out.
+ */
+static UmountStat TryUmountAndFsck(bool runFsck) {
+    std::vector<MountEntry> emulatedPartitions;
+    std::vector<MountEntry> blockDevRwPartitions;
+
+    TurnOffBacklight();  // this part can take time. save power.
+
+    if (!FindPartitionsToUmount(&blockDevRwPartitions, &emulatedPartitions)) {
+        return UMOUNT_STAT_ERROR;
+    }
+    if (emulatedPartitions.size() > 0) {
+        LOG(WARNING) << "emulated partitions still exist, will umount";
+        /* Pending writes in emulated partitions can fail umount. After a few trials, detach
+         * it so that it can be umounted when all writes are done.
+         */
+        if (!UmountPartitions(&emulatedPartitions, 1, 0)) {
+            UmountPartitions(&emulatedPartitions, 1, MNT_DETACH);
+        }
+    }
+    UmountStat stat = UMOUNT_STAT_SUCCESS;
+    /* data partition needs all pending writes to be completed and all emulated partitions
+     * umounted. If umount failed in the above step, it DETACH is requested, so umount can
+     * still happen while waiting for /data. If the current waiting is not good enough, give
+     * up and leave it to e2fsck after reboot to fix it.
+     */
+    /* TODO update max waiting time based on usage data */
+    if (!UmountPartitions(&blockDevRwPartitions, 100, 0)) {
+        /* Last resort, detach and hope it finish before shutdown. */
+        UmountPartitions(&blockDevRwPartitions, 1, MNT_DETACH);
+        stat = UMOUNT_STAT_TIMEOUT;
+    }
+    if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
+        for (auto& entry : blockDevRwPartitions) {
+            DoFsck(entry);
+        }
+    }
+
+    return stat;
+}
+
+static void DoSync() {
+    // quota sync is not done by sync cal, so should be done separately.
+    // quota sync is in VFS level, so do it before sync, which goes down to fs level.
+    int r = quotactl(QCMD(Q_SYNC, 0), nullptr, 0 /* do not care */, 0 /* do not care */);
+    if (r < 0) {
+        PLOG(ERROR) << "quotactl failed";
+    }
+    sync();
+}
+
+static void __attribute__((noreturn)) DoThermalOff() {
+    LOG(WARNING) << "Thermal system shutdown";
+    DoSync();
+    RebootSystem(ANDROID_RB_THERMOFF, "");
+    abort();
+}
+
+void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
+              bool runFsck) {
+    Timer t;
+    std::string timeout = property_get("ro.build.shutdown_timeout");
+    unsigned int delay = 0;
+
+    if (!android::base::ParseUint(timeout, &delay)) {
+        delay = 3;  // force service termination by default
+    }
+
+    android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE);
+
+    if (cmd == ANDROID_RB_THERMOFF) {  // do not wait if it is thermal
+        DoThermalOff();
+        abort();
+    }
+    static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
+    for (const char* name : shutdown_critical_services) {
+        Service* s = ServiceManager::GetInstance().FindServiceByName(name);
+        if (s == nullptr) {
+            LOG(WARNING) << "Shutdown critical service not found:" << name;
+            continue;
+        }
+        s->Start();  // make sure that it is running.
+        s->SetShutdownCritical();
+    }
+    // optional shutdown step
+    // 1. terminate all services except shutdown critical ones. wait for delay to finish
+    if (delay > 0) {
+        LOG(INFO) << "terminating init services";
+        // tombstoned can write to data when other services are killed. so finish it first.
+        static const constexpr char* first_to_kill[] = {"tombstoned"};
+        for (const char* name : first_to_kill) {
+            Service* s = ServiceManager::GetInstance().FindServiceByName(name);
+            if (s != nullptr) s->Stop();
+        }
+
+        // Ask all services to terminate except shutdown critical ones.
+        ServiceManager::GetInstance().ForEachService([](Service* s) {
+            if (!s->IsShutdownCritical()) s->Terminate();
+        });
+
+        int service_count = 0;
+        while (t.duration_s() < delay) {
+            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+
+            service_count = 0;
+            ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
+                // Count the number of services running except shutdown critical.
+                // Exclude the console as it will ignore the SIGTERM signal
+                // and not exit.
+                // Note: SVC_CONSOLE actually means "requires console" but
+                // it is only used by the shell.
+                if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
+                    service_count++;
+                }
+            });
+
+            if (service_count == 0) {
+                // All terminable services terminated. We can exit early.
+                break;
+            }
+
+            // Wait a bit before recounting the number or running services.
+            std::this_thread::sleep_for(50ms);
+        }
+        LOG(INFO) << "Terminating running services took " << t
+                  << " with remaining services:" << service_count;
+    }
+
+    // minimum safety steps before restarting
+    // 2. kill all services except ones that are necessary for the shutdown sequence.
+    ServiceManager::GetInstance().ForEachService([](Service* s) {
+        if (!s->IsShutdownCritical()) s->Stop();
+    });
+    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+
+    // 3. send volume shutdown to vold
+    Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
+    if (voldService != nullptr && voldService->IsRunning()) {
+        ShutdownVold();
+        voldService->Terminate();
+    } else {
+        LOG(INFO) << "vold not running, skipping vold shutdown";
+    }
+
+    // 4. sync, try umount, and optionally run fsck for user shutdown
+    DoSync();
+    UmountStat stat = TryUmountAndFsck(runFsck);
+    LogShutdownTime(stat, &t);
+    // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
+    RebootSystem(cmd, rebootTarget);
+    abort();
+}
diff --git a/init/reboot.h b/init/reboot.h
new file mode 100644
index 0000000..3956249
--- /dev/null
+++ b/init/reboot.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _INIT_REBOOT_H
+#define _INIT_REBOOT_H
+
+/* Reboot / shutdown the system.
+ * cmd ANDROID_RB_* as defined in android_reboot.h
+ * reason Reason string like "reboot", "userrequested"
+ * rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
+ *              empty string.
+ * runFsck Whether to run fsck after umount is done.
+ */
+void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
+              bool runFsck) __attribute__((__noreturn__));
+
+#endif
diff --git a/init/service.h b/init/service.h
index 013e65f..08388e2 100644
--- a/init/service.h
+++ b/init/service.h
@@ -32,18 +32,21 @@
 #include "keyword_map.h"
 #include "util.h"
 
-#define SVC_DISABLED       0x001  // do not autostart with class
-#define SVC_ONESHOT        0x002  // do not restart on exit
-#define SVC_RUNNING        0x004  // currently active
-#define SVC_RESTARTING     0x008  // waiting to restart
-#define SVC_CONSOLE        0x010  // requires console
-#define SVC_CRITICAL       0x020  // will reboot into recovery if keeps crashing
-#define SVC_RESET          0x040  // Use when stopping a process,
+#define SVC_DISABLED 0x001        // do not autostart with class
+#define SVC_ONESHOT 0x002         // do not restart on exit
+#define SVC_RUNNING 0x004         // currently active
+#define SVC_RESTARTING 0x008      // waiting to restart
+#define SVC_CONSOLE 0x010         // requires console
+#define SVC_CRITICAL 0x020        // will reboot into recovery if keeps crashing
+#define SVC_RESET 0x040           // Use when stopping a process,
                                   // but not disabling so it can be restarted with its class.
-#define SVC_RC_DISABLED    0x080  // Remember if the disabled flag was set in the rc script.
-#define SVC_RESTART        0x100  // Use to safely restart (stop, wait, start) a service.
+#define SVC_RC_DISABLED 0x080     // Remember if the disabled flag was set in the rc script.
+#define SVC_RESTART 0x100         // Use to safely restart (stop, wait, start) a service.
 #define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
-#define SVC_EXEC           0x400  // This synthetic service corresponds to an 'exec'.
+#define SVC_EXEC 0x400            // This synthetic service corresponds to an 'exec'.
+
+#define SVC_SHUTDOWN_CRITICAL 0x800  // This service is critical for shutdown and
+                                     // should not be killed during shutdown
 
 #define NR_SVC_SUPP_GIDS 12    // twelve supplementary groups
 
@@ -68,6 +71,7 @@
             unsigned namespace_flags, const std::string& seclabel,
             const std::vector<std::string>& args);
 
+    bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     bool ParseLine(const std::vector<std::string>& args, std::string* err);
     bool Start();
     bool StartIfNotDisabled();
@@ -79,6 +83,8 @@
     void RestartIfNeeded(time_t* process_needs_restart_at);
     bool Reap();
     void DumpState() const;
+    void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
+    bool IsShutdownCritical() { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
 
     const std::string& name() const { return name_; }
     const std::string& classname() const { return classname_; }
diff --git a/init/util.cpp b/init/util.cpp
index c987181..b90e5b1 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -49,6 +49,7 @@
 #include "init.h"
 #include "log.h"
 #include "property_service.h"
+#include "reboot.h"
 #include "util.h"
 
 static unsigned int do_decode_uid(const char *s)
@@ -410,18 +411,9 @@
     return true;
 }
 
-void reboot(const char* destination) {
-    android_reboot(ANDROID_RB_RESTART2, 0, destination);
-    // We're init, so android_reboot will actually have been a syscall so there's nothing
-    // to wait for. If android_reboot returns, just abort so that the kernel will reboot
-    // itself when init dies.
-    PLOG(FATAL) << "reboot failed";
-    abort();
-}
-
 void panic() {
     LOG(ERROR) << "panic: rebooting to bootloader";
-    reboot("bootloader");
+    DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
 }
 
 std::ostream& operator<<(std::ostream& os, const Timer& t) {
diff --git a/init/util.h b/init/util.h
index 5c38dc3..81c64d7 100644
--- a/init/util.h
+++ b/init/util.h
@@ -78,7 +78,6 @@
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
 
-void reboot(const char* destination) __attribute__((__noreturn__));
 void panic() __attribute__((__noreturn__));
 
 #endif
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 0d2e11b..4354f0b 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -52,7 +52,16 @@
   }
 }
 
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset, const backtrace_map_t* map) {
+  backtrace_map_t map_value;
+  if (map == nullptr) {
+    FillInMap(pc, &map_value);
+    map = &map_value;
+  }
+  // If no map is found, or this map is backed by a device, then return nothing.
+  if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
+    return "";
+  }
   std::string func_name = GetFunctionNameRaw(pc, offset);
   return func_name;
 }
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 4862d9d..3c509e6 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -127,7 +127,7 @@
       if (num_ignore_frames == 0) {
         // GetFunctionName is an expensive call, only do it if we are
         // keeping the frame.
-        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
         if (num_frames > 0) {
           // Set the stack size for the previous frame.
           backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
@@ -143,6 +143,16 @@
         frames_.resize(0);
       }
     }
+    // If the pc is in a device map, then don't try to step.
+    if (frame->map.flags & PROT_DEVICE_MAP) {
+      break;
+    }
+    // Verify the sp is not in a device map too.
+    backtrace_map_t map;
+    FillInMap(frame->sp, &map);
+    if (map.flags & PROT_DEVICE_MAP) {
+      break;
+    }
     ret = unw_step (cursor.get());
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 5c73bd6..42ac1bc 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -136,12 +136,28 @@
 
       FillInMap(frame->pc, &frame->map);
 
-      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
 
       num_frames++;
+      // If the pc is in a device map, then don't try to step.
+      if (frame->map.flags & PROT_DEVICE_MAP) {
+        break;
+      }
     } else {
+      // If the pc is in a device map, then don't try to step.
+      backtrace_map_t map;
+      FillInMap(pc, &map);
+      if (map.flags & PROT_DEVICE_MAP) {
+        break;
+      }
       num_ignore_frames--;
     }
+    // Verify the sp is not in a device map.
+    backtrace_map_t map;
+    FillInMap(sp, &map);
+    if (map.flags & PROT_DEVICE_MAP) {
+      break;
+    }
     ret = unw_step (&cursor);
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9ca373a..24e48cd 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -42,6 +42,7 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <cutils/atomic.h>
@@ -1436,6 +1437,171 @@
   FinishRemoteProcess(pid);
 }
 
+static void SetUcontextSp(uintptr_t sp, ucontext_t* ucontext) {
+#if defined(__arm__)
+  ucontext->uc_mcontext.arm_sp = sp;
+#elif defined(__aarch64__)
+  ucontext->uc_mcontext.sp = sp;
+#elif defined(__i386__)
+  ucontext->uc_mcontext.gregs[REG_ESP] = sp;
+#elif defined(__x86_64__)
+  ucontext->uc_mcontext.gregs[REG_RSP] = sp;
+#else
+  UNUSED(sp);
+  UNUSED(ucontext);
+  ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static void SetUcontextPc(uintptr_t pc, ucontext_t* ucontext) {
+#if defined(__arm__)
+  ucontext->uc_mcontext.arm_pc = pc;
+#elif defined(__aarch64__)
+  ucontext->uc_mcontext.pc = pc;
+#elif defined(__i386__)
+  ucontext->uc_mcontext.gregs[REG_EIP] = pc;
+#elif defined(__x86_64__)
+  ucontext->uc_mcontext.gregs[REG_RIP] = pc;
+#else
+  UNUSED(pc);
+  UNUSED(ucontext);
+  ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static void SetUcontextLr(uintptr_t lr, ucontext_t* ucontext) {
+#if defined(__arm__)
+  ucontext->uc_mcontext.arm_lr = lr;
+#elif defined(__aarch64__)
+  ucontext->uc_mcontext.regs[30] = lr;
+#elif defined(__i386__)
+  // The lr is on the stack.
+  ASSERT_TRUE(lr != 0);
+  ASSERT_TRUE(ucontext != nullptr);
+#elif defined(__x86_64__)
+  // The lr is on the stack.
+  ASSERT_TRUE(lr != 0);
+  ASSERT_TRUE(ucontext != nullptr);
+#else
+  UNUSED(lr);
+  UNUSED(ucontext);
+  ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static constexpr size_t DEVICE_MAP_SIZE = 1024;
+
+static void SetupDeviceMap(void** device_map) {
+  // Make sure that anything in a device map will result in fails
+  // to read.
+  android::base::unique_fd device_fd(open("/dev/zero", O_RDONLY | O_CLOEXEC));
+
+  *device_map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE, device_fd, 0);
+  ASSERT_TRUE(*device_map != MAP_FAILED);
+
+  // Make sure the map is readable.
+  ASSERT_EQ(0, reinterpret_cast<int*>(*device_map)[0]);
+}
+
+static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
+  uintptr_t device_map_uint = reinterpret_cast<uintptr_t>(device_map);
+
+  backtrace_map_t map;
+  backtrace->FillInMap(device_map_uint, &map);
+  // Verify the flag is set.
+  ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
+
+  // Quick sanity checks.
+  size_t offset;
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
+
+  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
+  // Now verify the device map flag actually causes the function name to be empty.
+  backtrace->FillInMap(cur_func_offset, &map);
+  ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
+  ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
+  map.flags |= PROT_DEVICE_MAP;
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
+
+  ucontext_t ucontext;
+
+  // Create a context that has the pc in the device map, but the sp
+  // in a non-device map.
+  memset(&ucontext, 0, sizeof(ucontext));
+  SetUcontextSp(reinterpret_cast<uintptr_t>(&ucontext), &ucontext);
+  SetUcontextPc(device_map_uint, &ucontext);
+  SetUcontextLr(cur_func_offset, &ucontext);
+
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  // The buffer should only be a single element.
+  ASSERT_EQ(1U, backtrace->NumFrames());
+  const backtrace_frame_data_t* frame = backtrace->GetFrame(0);
+  ASSERT_EQ(device_map_uint, frame->pc);
+  ASSERT_EQ(reinterpret_cast<uintptr_t>(&ucontext), frame->sp);
+
+  // Check what happens when skipping the first frame.
+  ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
+  ASSERT_EQ(0U, backtrace->NumFrames());
+
+  // Create a context that has the sp in the device map, but the pc
+  // in a non-device map.
+  memset(&ucontext, 0, sizeof(ucontext));
+  SetUcontextSp(device_map_uint, &ucontext);
+  SetUcontextPc(cur_func_offset, &ucontext);
+  SetUcontextLr(cur_func_offset, &ucontext);
+
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  // The buffer should only be a single element.
+  ASSERT_EQ(1U, backtrace->NumFrames());
+  frame = backtrace->GetFrame(0);
+  ASSERT_EQ(cur_func_offset, frame->pc);
+  ASSERT_EQ(device_map_uint, frame->sp);
+
+  // Check what happens when skipping the first frame.
+  ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
+  ASSERT_EQ(0U, backtrace->NumFrames());
+}
+
+TEST(libbacktrace, unwind_disallow_device_map_local) {
+  void* device_map;
+  SetupDeviceMap(&device_map);
+
+  // Now create an unwind object.
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace);
+
+  UnwindFromDevice(backtrace.get(), device_map);
+
+  munmap(device_map, DEVICE_MAP_SIZE);
+}
+
+TEST(libbacktrace, unwind_disallow_device_map_remote) {
+  void* device_map;
+  SetupDeviceMap(&device_map);
+
+  // Fork a process to do a remote backtrace.
+  pid_t pid;
+  CreateRemoteProcess(&pid);
+
+  // Now create an unwind object.
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+
+  // TODO: Currently unwind from context doesn't work on remote
+  // unwind. Keep this test because the new unwinder should support
+  // this eventually, or we can delete this test.
+  // properly with unwind from context.
+  // UnwindFromDevice(backtrace.get(), device_map);
+
+  FinishRemoteProcess(pid);
+
+  munmap(device_map, DEVICE_MAP_SIZE);
+}
+
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 06026d1..a33e45f 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -13,259 +13,39 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <mntent.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/reboot.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 #include <cutils/android_reboot.h>
-#include <cutils/klog.h>
-#include <cutils/list.h>
+#include <cutils/properties.h>
 
 #define TAG "android_reboot"
-#define READONLY_CHECK_MS 5000
-#define READONLY_CHECK_TIMES 50
 
-typedef struct {
-    struct listnode list;
-    struct mntent entry;
-} mntent_list;
-
-static bool is_block_device(const char* fsname)
-{
-    return !strncmp(fsname, "/dev/block", 10);
-}
-
-/* Find all read+write block devices in /proc/mounts and add them to
- * |rw_entries|.
- */
-static void find_rw(struct listnode* rw_entries)
-{
-    FILE* fp;
-    struct mntent* mentry;
-
-    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
-        KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
-        return;
-    }
-    while ((mentry = getmntent(fp)) != NULL) {
-        if (is_block_device(mentry->mnt_fsname) && hasmntopt(mentry, "rw")) {
-            mntent_list* item = (mntent_list*)calloc(1, sizeof(mntent_list));
-            item->entry = *mentry;
-            item->entry.mnt_fsname = strdup(mentry->mnt_fsname);
-            item->entry.mnt_dir = strdup(mentry->mnt_dir);
-            item->entry.mnt_type = strdup(mentry->mnt_type);
-            item->entry.mnt_opts = strdup(mentry->mnt_opts);
-            list_add_tail(rw_entries, &item->list);
-        }
-    }
-    endmntent(fp);
-}
-
-static void free_entries(struct listnode* entries)
-{
-    struct listnode* node;
-    struct listnode* n;
-    list_for_each_safe(node, n, entries) {
-        mntent_list* item = node_to_item(node, mntent_list, list);
-        free(item->entry.mnt_fsname);
-        free(item->entry.mnt_dir);
-        free(item->entry.mnt_type);
-        free(item->entry.mnt_opts);
-        free(item);
-    }
-}
-
-static mntent_list* find_item(struct listnode* rw_entries, const char* fsname_to_find)
-{
-    struct listnode* node;
-    list_for_each(node, rw_entries) {
-        mntent_list* item = node_to_item(node, mntent_list, list);
-        if (!strcmp(item->entry.mnt_fsname, fsname_to_find)) {
-            return item;
-        }
-    }
-    return NULL;
-}
-
-/* Remounting filesystems read-only is difficult when there are files
- * opened for writing or pending deletes on the filesystem.  There is
- * no way to force the remount with the mount(2) syscall.  The magic sysrq
- * 'u' command does an emergency remount read-only on all writable filesystems
- * that have a block device (i.e. not tmpfs filesystems) by calling
- * emergency_remount(), which knows how to force the remount to read-only.
- * Unfortunately, that is asynchronous, and just schedules the work and
- * returns.  The best way to determine if it is done is to read /proc/mounts
- * repeatedly until there are no more writable filesystems mounted on
- * block devices.
- */
-static void remount_ro(void (*cb_on_remount)(const struct mntent*))
-{
-    int fd, cnt;
-    FILE* fp;
-    struct mntent* mentry;
-    struct listnode* node;
-
-    list_declare(rw_entries);
-    list_declare(ro_entries);
-
-    sync();
-    find_rw(&rw_entries);
-
-    /* Trigger the remount of the filesystems as read-only,
-     * which also marks them clean.
-     */
-    fd = TEMP_FAILURE_RETRY(open("/proc/sysrq-trigger", O_WRONLY));
-    if (fd < 0) {
-        KLOG_WARNING(TAG, "Failed to open sysrq-trigger.\n");
-        /* TODO: Try to remount each rw parition manually in readonly mode.
-         * This may succeed if no process is using the partition.
-         */
-        goto out;
-    }
-    if (TEMP_FAILURE_RETRY(write(fd, "u", 1)) != 1) {
-        close(fd);
-        KLOG_WARNING(TAG, "Failed to write to sysrq-trigger.\n");
-        /* TODO: The same. Manually remount the paritions. */
-        goto out;
-    }
-    close(fd);
-
-    /* Now poll /proc/mounts till it's done */
-    cnt = 0;
-    while (cnt < READONLY_CHECK_TIMES) {
-        if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
-            /* If we can't read /proc/mounts, just give up. */
-            KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
-            goto out;
-        }
-        while ((mentry = getmntent(fp)) != NULL) {
-            if (!is_block_device(mentry->mnt_fsname) || !hasmntopt(mentry, "ro")) {
-                continue;
-            }
-            mntent_list* item = find_item(&rw_entries, mentry->mnt_fsname);
-            if (item) {
-                /* |item| has now been ro remounted. */
-                list_remove(&item->list);
-                list_add_tail(&ro_entries, &item->list);
-            }
-        }
-        endmntent(fp);
-        if (list_empty(&rw_entries)) {
-            /* All rw block devices are now readonly. */
-            break;
-        }
-        TEMP_FAILURE_RETRY(
-            usleep(READONLY_CHECK_MS * 1000 / READONLY_CHECK_TIMES));
-        cnt++;
-    }
-
-    list_for_each(node, &rw_entries) {
-        mntent_list* item = node_to_item(node, mntent_list, list);
-        KLOG_WARNING(TAG, "Failed to remount %s in readonly mode.\n",
-                     item->entry.mnt_fsname);
-    }
-
-    if (cb_on_remount) {
-        list_for_each(node, &ro_entries) {
-            mntent_list* item = node_to_item(node, mntent_list, list);
-            cb_on_remount(&item->entry);
-        }
-    }
-
-out:
-    free_entries(&rw_entries);
-    free_entries(&ro_entries);
-}
-
-static void save_reboot_reason(int cmd, const char *arg)
-{
-    FILE *fp;
-    const char *reason = NULL;
-
-    fp = fopen(LAST_REBOOT_REASON_FILE, "w");
-    if (fp == NULL) {
-        KLOG_WARNING(TAG, "Error creating " LAST_REBOOT_REASON_FILE
-                     ": %s\n", strerror(errno));
-        return;
-    }
-    switch (cmd) {
-        case ANDROID_RB_RESTART:
-            reason = "restart";
-            break;
-
-        case ANDROID_RB_POWEROFF:
-            reason = "power-off";
-            break;
-
-        case ANDROID_RB_RESTART2:
-            reason = arg && strlen(arg) ? arg : "restart";
-            break;
-
-        case ANDROID_RB_THERMOFF:
-            reason = "thermal-shutdown";
-            break;
-
-        default:
-            fprintf(fp,"0x%08X\n", cmd);
-            break;
-    }
-
-    if (reason) {
-        if (fprintf(fp, "%s\n", reason) < 0) {
-             KLOG_WARNING(TAG, "Error writing " LAST_REBOOT_REASON_FILE
-                          ": %s\n", strerror(errno));
-        }
-    }
-
-    fclose(fp);
-}
-
-int android_reboot_with_callback(
-    int cmd, int flags __unused, const char *arg,
-    void (*cb_on_remount)(const struct mntent*))
-{
+int android_reboot(int cmd, int flags __unused, const char* arg) {
     int ret;
+    const char* restart_cmd = NULL;
+    char* prop_value;
 
-    save_reboot_reason(cmd, arg);
-    remount_ro(cb_on_remount);
     switch (cmd) {
-        case ANDROID_RB_RESTART:
-            ret = reboot(RB_AUTOBOOT);
-            break;
-
-        case ANDROID_RB_POWEROFF:
-            ret = reboot(RB_POWER_OFF);
-            break;
-
+        case ANDROID_RB_RESTART:  // deprecated
         case ANDROID_RB_RESTART2:
-            ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
-                           LINUX_REBOOT_CMD_RESTART2, arg);
+            restart_cmd = "reboot";
             break;
-
+        case ANDROID_RB_POWEROFF:
+            restart_cmd = "shutdown";
+            break;
         case ANDROID_RB_THERMOFF:
-            ret = reboot(RB_POWER_OFF);
+            restart_cmd = "thermal-shutdown";
             break;
-
-        default:
-            ret = -1;
     }
-
+    if (!restart_cmd) return -1;
+    if (arg) {
+        ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg);
+    } else {
+        ret = asprintf(&prop_value, "%s", restart_cmd);
+    }
+    if (ret < 0) return -1;
+    ret = property_set(ANDROID_RB_PROPERTY, prop_value);
+    free(prop_value);
     return ret;
 }
-
-int android_reboot(int cmd, int flags, const char *arg)
-{
-    return android_reboot_with_callback(cmd, flags, arg, NULL);
-}
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index 2e3b429..716567a 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -17,12 +17,11 @@
 #ifndef __CUTILS_ANDROID_REBOOT_H__
 #define __CUTILS_ANDROID_REBOOT_H__
 
-#include <mntent.h>
 
 __BEGIN_DECLS
 
 /* Commands */
-#define ANDROID_RB_RESTART  0xDEAD0001
+#define ANDROID_RB_RESTART 0xDEAD0001 /* deprecated. Use RESTART2. */
 #define ANDROID_RB_POWEROFF 0xDEAD0002
 #define ANDROID_RB_RESTART2 0xDEAD0003
 #define ANDROID_RB_THERMOFF 0xDEAD0004
@@ -33,10 +32,12 @@
 /* Android reboot reason stored in this file */
 #define LAST_REBOOT_REASON_FILE "/data/misc/reboot/last_reboot_reason"
 
+/* Reboot or shutdown the system.
+ * This call uses ANDROID_RB_PROPERTY to request reboot to init process.
+ * Due to that, process calling this should have proper selinux permission
+ * to write to the property. Otherwise, the call will fail.
+ */
 int android_reboot(int cmd, int flags, const char *arg);
-int android_reboot_with_callback(
-    int cmd, int flags, const char *arg,
-    void (*cb_on_remount)(const struct mntent*));
 
 __END_DECLS
 
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 7ee0464..ccb1aa6 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -32,3 +32,22 @@
         "-Werror",
     ],
 }
+
+// ========================================================
+// Benchmark
+// ========================================================
+cc_benchmark {
+    name: "android_fork_execvp_ext_benchmark",
+    srcs: [
+        "android_fork_execvp_ext_benchmark.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+    ],
+    cflags: [
+        "-Werror",
+    ]
+}
diff --git a/logwrapper/android_fork_execvp_ext_benchmark.cpp b/logwrapper/android_fork_execvp_ext_benchmark.cpp
new file mode 100644
index 0000000..1abd932
--- /dev/null
+++ b/logwrapper/android_fork_execvp_ext_benchmark.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 "logwrap/logwrap.h"
+
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+
+static void BM_android_fork_execvp_ext(benchmark::State& state) {
+    const char* argv[] = {"/system/bin/echo", "hello", "world"};
+    const int argc = 3;
+    while (state.KeepRunning()) {
+        int rc = android_fork_execvp_ext(
+            argc, (char**)argv, NULL /* status */, false /* ignore_int_quit */, LOG_NONE,
+            false /* abbreviated */, NULL /* file_path */, NULL /* opts */, 0 /* opts_len */);
+        CHECK_EQ(0, rc);
+    }
+}
+BENCHMARK(BM_android_fork_execvp_ext);
+
+BENCHMARK_MAIN();
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 89a8fdd..d3538b3 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -54,9 +54,8 @@
  *           the specified log until the child has exited.
  *   file_path: if log_target has the LOG_FILE bit set, then this parameter
  *           must be set to the pathname of the file to log to.
- *   opts: set to non-NULL if you want to use one or more of the
- *           FORK_EXECVP_OPTION_* features.
- *   opts_len: the length of the opts array. When opts is NULL, pass 0.
+ *   unused_opts: currently unused.
+ *   unused_opts_len: currently unused.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -72,30 +71,10 @@
 #define LOG_KLOG        2
 #define LOG_FILE        4
 
-/* Write data to child's stdin. */
-#define FORK_EXECVP_OPTION_INPUT             0
-/* Capture data from child's stdout and stderr. */
-#define FORK_EXECVP_OPTION_CAPTURE_OUTPUT    1
-
-struct AndroidForkExecvpOption {
-    int opt_type;
-    union {
-        struct {
-            const uint8_t* input;
-            size_t input_len;
-        } opt_input;
-        struct {
-            void (*on_output)(const uint8_t* /*output*/,
-                              size_t /*output_len*/,
-                              void* /* user_pointer */);
-            void* user_pointer;
-        } opt_capture_output;
-    };
-};
-
+// TODO: Remove unused_opts / unused_opts_len in a followup change.
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated, char *file_path,
-        const struct AndroidForkExecvpOption* opts, size_t opts_len);
+        int log_target, bool abbreviated, char *file_path, void* unused_opts,
+        int unused_opts_len);
 
 /* Similar to above, except abbreviated logging is not available, and if logwrap
  * is true, logging is to the Android system log, and if false, there is no
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 3ad0983..7076078 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -291,8 +291,7 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated, char *file_path,
-        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -359,13 +358,6 @@
             sz = TEMP_FAILURE_RETRY(
                 read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
 
-            for (size_t i = 0; sz > 0 && i < opts_len; ++i) {
-                if (opts[i].opt_type == FORK_EXECVP_OPTION_CAPTURE_OUTPUT) {
-                  opts[i].opt_capture_output.on_output(
-                      (uint8_t*)&buffer[b], sz, opts[i].opt_capture_output.user_pointer);
-                }
-            }
-
             sz += b;
             // Log one line at a time
             for (b = 0; b < sz; b++) {
@@ -483,7 +475,7 @@
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
         int log_target, bool abbreviated, char *file_path,
-        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
+        void *unused_opts, int unused_opts_len) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -493,6 +485,9 @@
     sigset_t oldset;
     int rc = 0;
 
+    LOG_ALWAYS_FATAL_IF(unused_opts != NULL);
+    LOG_ALWAYS_FATAL_IF(unused_opts_len != 0);
+
     rc = pthread_mutex_lock(&fd_mutex);
     if (rc) {
         ERROR("failed to lock signal_fd mutex\n");
@@ -538,13 +533,6 @@
         pthread_sigmask(SIG_SETMASK, &oldset, NULL);
         close(parent_ptty);
 
-        // redirect stdin, stdout and stderr
-        for (size_t i = 0; i < opts_len; ++i) {
-            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
-                dup2(child_ptty, 0);
-                break;
-            }
-        }
         dup2(child_ptty, 1);
         dup2(child_ptty, 2);
         close(child_ptty);
@@ -561,24 +549,8 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        for (size_t i = 0; i < opts_len; ++i) {
-            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
-                size_t left = opts[i].opt_input.input_len;
-                const uint8_t* input = opts[i].opt_input.input;
-                while (left > 0) {
-                    ssize_t res =
-                        TEMP_FAILURE_RETRY(write(parent_ptty, input, left));
-                    if (res < 0) {
-                        break;
-                    }
-                    left -= res;
-                    input += res;
-                }
-            }
-        }
-
         rc = parent(argv[0], parent_ptty, pid, status, log_target,
-                    abbreviated, file_path, opts, opts_len);
+                    abbreviated, file_path);
     }
 
     if (ignore_int_quit) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index dcb3b25..06dc88b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -346,6 +346,9 @@
     # create the lost+found directories, so as to enforce our permissions
     mkdir /cache/lost+found 0770 root root
 
+on late-fs
+    start hwservicemanager
+
 on post-fs-data
     # We chown/chmod /data again so because mount is run as root + defaults
     chown system system /data
@@ -586,8 +589,9 @@
     # Define default initial receive window size in segments.
     setprop net.tcp.default_init_rwnd 60
 
-    # Start all binderized HAL daemons
-    start hwservicemanager
+    # Start standard binderized HAL daemons
+    class_start hal
+
     class_start core
 
 on nonencrypted