reboot.cpp revision 2ba5c8103d0cf748fdf03c9e5be975ccc36fb56a
18d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park/*
28d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * Copyright (C) 2017 The Android Open Source Project
38d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park *
48d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * Licensed under the Apache License, Version 2.0 (the "License");
58d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * you may not use this file except in compliance with the License.
68d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * You may obtain a copy of the License at
78d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park *
88d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park *      http://www.apache.org/licenses/LICENSE-2.0
98d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park *
108d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * Unless required by applicable law or agreed to in writing, software
118d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * distributed under the License is distributed on an "AS IS" BASIS,
128d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * See the License for the specific language governing permissions and
148d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * limitations under the License.
158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park */
163f5eaae526413a29de899270714469c76dc91ec8Tom Cherry
173f5eaae526413a29de899270714469c76dc91ec8Tom Cherry#include "reboot.h"
183f5eaae526413a29de899270714469c76dc91ec8Tom Cherry
198d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <dirent.h>
208d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <fcntl.h>
212ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park#include <linux/fs.h>
228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <mntent.h>
232ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park#include <selinux/selinux.h>
248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/cdefs.h>
252ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park#include <sys/ioctl.h>
268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/mount.h>
278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/reboot.h>
288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/stat.h>
298d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/syscall.h>
308d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/types.h>
318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/wait.h>
328d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <memory>
347830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park#include <set>
358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <thread>
368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <vector>
378d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/file.h>
393f5eaae526413a29de899270714469c76dc91ec8Tom Cherry#include <android-base/logging.h>
408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/macros.h>
41ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/properties.h>
428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/stringprintf.h>
438d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/strings.h>
442ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park#include <android-base/unique_fd.h>
458d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <bootloader_message/bootloader_message.h>
468d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <cutils/android_reboot.h>
478d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <fs_mgr.h>
488d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <logwrap/logwrap.h>
498d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
507830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park#include "property_service.h"
518d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include "service.h"
528d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
538d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkusing android::base::StringPrintf;
548d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
558d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park// represents umount status during reboot / shutdown.
568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkenum UmountStat {
578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* umount succeeded. */
588d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_SUCCESS = 0,
598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* umount was not run. */
608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_SKIPPED = 1,
618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* umount failed with timeout. */
628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_TIMEOUT = 2,
638d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* could not run due to error */
648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_ERROR = 3,
658d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* not used by init but reserved for other part to use this to represent the
668d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park       the state where umount status before reboot is not found / available. */
678d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_NOT_AVAILABLE = 4,
688d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park};
698d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park// Utility for struct mntent
718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkclass MountEntry {
728d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park  public:
732ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    explicit MountEntry(const mntent& entry)
748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        : mnt_fsname_(entry.mnt_fsname),
758d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park          mnt_dir_(entry.mnt_dir),
768d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park          mnt_type_(entry.mnt_type),
772ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park          mnt_opts_(entry.mnt_opts) {}
788d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
792ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    bool Umount() {
802ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        int r = umount2(mnt_dir_.c_str(), 0);
812ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (r == 0) {
822ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            LOG(INFO) << "umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
832ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            return true;
842ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        } else {
852ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            PLOG(WARNING) << "cannot umount " << mnt_fsname_ << ":" << mnt_dir_ << " opts "
862ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                          << mnt_opts_;
872ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            return false;
882ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        }
892ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    }
908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
912ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    void DoFsck() {
922ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        int st;
932ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (IsF2Fs()) {
942ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            const char* f2fs_argv[] = {
952ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                "/system/bin/fsck.f2fs", "-f", mnt_fsname_.c_str(),
962ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            };
972ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG,
982ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                                    true, nullptr, nullptr, 0);
992ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        } else if (IsExt4()) {
1002ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            const char* ext4_argv[] = {
1012ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                "/system/bin/e2fsck", "-f", "-y", mnt_fsname_.c_str(),
1022ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            };
1032ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG,
1042ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                                    true, nullptr, nullptr, 0);
1052ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        }
1062ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    }
1078d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1088d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static bool IsBlockDevice(const struct mntent& mntent) {
1098d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
1108d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1118d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1128d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static bool IsEmulatedDevice(const struct mntent& mntent) {
1132ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        return android::base::StartsWith(mntent.mnt_fsname, "/data/");
1148d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1168d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park  private:
1172ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
1182ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park
1192ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    bool IsExt4() const { return mnt_type_ == "ext4"; }
1202ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park
1218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::string mnt_fsname_;
1228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::string mnt_dir_;
1238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::string mnt_type_;
1242ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    std::string mnt_opts_;
1258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park};
1268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park// Turn off backlight while we are performing power down cleanup activities.
1288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void TurnOffBacklight() {
1298d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static constexpr char OFF[] = "0";
1308d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
1328d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static const char backlightDir[] = "/sys/class/backlight";
1348d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
1358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (!dir) {
1368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return;
1378d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1398d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    struct dirent* dp;
1408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while ((dp = readdir(dir.get())) != nullptr) {
1418d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
1428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            continue;
1438d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
1448d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1458d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
1468d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        android::base::WriteStringToFile(OFF, fileName);
1478d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1488d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1498d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1508d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void ShutdownVold() {
1518d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
1528d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    int status;
1538d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true, LOG_KLOG, true,
1548d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                            nullptr, nullptr, 0);
1558d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void LogShutdownTime(UmountStat stat, Timer* t) {
1588d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
1598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void __attribute__((noreturn))
1628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young ParkRebootSystem(unsigned int cmd, const std::string& rebootTarget) {
1633cd8c6f9123883d02e1c4c146e1ef7bfcfa170a3Keun-young Park    LOG(INFO) << "Reboot ending, jumping to kernel";
1648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    switch (cmd) {
1658d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        case ANDROID_RB_POWEROFF:
1668d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            reboot(RB_POWER_OFF);
1678d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1688d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1698d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        case ANDROID_RB_RESTART2:
1708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
1718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
1728d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1738d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        case ANDROID_RB_THERMOFF:
1758d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            reboot(RB_POWER_OFF);
1768d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1778d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1788d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // In normal case, reboot should not return.
1798d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    PLOG(FATAL) << "reboot call returned";
1808d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    abort();
1818d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1828d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1838d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park/* Find all read+write block devices and emulated devices in /proc/mounts
1848d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * and add them to correpsponding list.
1858d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park */
1868d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
1872ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                                   std::vector<MountEntry>* emulatedPartitions, bool dump) {
1888d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
1898d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (fp == nullptr) {
1908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        PLOG(ERROR) << "Failed to open /proc/mounts";
1918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return false;
1928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    mntent* mentry;
1948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while ((mentry = getmntent(fp.get())) != nullptr) {
1952ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (dump) {
1962ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            LOG(INFO) << "mount entry " << mentry->mnt_fsname << ":" << mentry->mnt_dir << " opts "
1972ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                      << mentry->mnt_opts << " type " << mentry->mnt_type;
1982ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        } else if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
1992ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
2008d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        } else if (MountEntry::IsEmulatedDevice(*mentry)) {
2012ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            emulatedPartitions->emplace(emulatedPartitions->begin(), *mentry);
2028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
2038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2048d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    return true;
2058d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
2068d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2072ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Parkstatic void DumpUmountDebuggingInfo() {
2082ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    int status;
2092ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    if (!security_getenforce()) {
2102ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        LOG(INFO) << "Run lsof";
2112ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        const char* lsof_argv[] = {"/system/bin/lsof"};
2122ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        android_fork_execvp_ext(arraysize(lsof_argv), (char**)lsof_argv, &status, true, LOG_KLOG,
2132ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                                true, nullptr, nullptr, 0);
2142ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    }
2152ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    FindPartitionsToUmount(nullptr, nullptr, true);
2162ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park}
2178d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2182ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Parkstatic UmountStat UmountPartitions(int timeoutMs) {
2192ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    Timer t;
2202ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    UmountStat stat = UMOUNT_STAT_TIMEOUT;
2212ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    int retry = 0;
2222ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    /* data partition needs all pending writes to be completed and all emulated partitions
2232ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park     * umounted.If the current waiting is not good enough, give
2242ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park     * up and leave it to e2fsck after reboot to fix it.
2252ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park     */
2268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while (true) {
2272ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        std::vector<MountEntry> block_devices;
2282ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        std::vector<MountEntry> emulated_devices;
2292ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (!FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
2302ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            return UMOUNT_STAT_ERROR;
2318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
2322ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (block_devices.size() == 0) {
2332ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            stat = UMOUNT_STAT_SUCCESS;
2342ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            break;
2352ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        }
2362ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if ((timeoutMs < t.duration_ms()) && retry > 0) {  // try umount at least once
2372ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            stat = UMOUNT_STAT_TIMEOUT;
2382ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            break;
2392ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        }
2402ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (emulated_devices.size() > 0 &&
2412ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            std::all_of(emulated_devices.begin(), emulated_devices.end(),
2422ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park                        [](auto& entry) { return entry.Umount(); })) {
2432ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            sync();
2442ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        }
2452ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        for (auto& entry : block_devices) {
2462ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            entry.Umount();
2472ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        }
2482ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        retry++;
2492ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        std::this_thread::sleep_for(100ms);
2508d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2512ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    return stat;
2528d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
2538d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2543ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Parkstatic void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
2553ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park
2568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park/* Try umounting all emulated file systems R/W block device cfile systems.
2578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * This will just try umount and give it up if it fails.
2588d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * For fs like ext4, this is ok as file system will be marked as unclean shutdown
2598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * and necessary check can be done at the next reboot.
2608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * For safer shutdown, caller needs to make sure that
2618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * all processes / emulated partition for the target fs are all cleaned-up.
2628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park *
2638d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * return true when umount was successful. false when timed out.
2648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park */
2653ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Parkstatic UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
2663ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    Timer t;
2672ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    std::vector<MountEntry> block_devices;
2682ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    std::vector<MountEntry> emulated_devices;
2698d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    TurnOffBacklight();  // this part can take time. save power.
2718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2722ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    if (runFsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
2738d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return UMOUNT_STAT_ERROR;
2748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2752ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park
2762ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    UmountStat stat = UmountPartitions(timeoutMs - t.duration_ms());
2772ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    if (stat != UMOUNT_STAT_SUCCESS) {
2782ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        LOG(INFO) << "umount timeout, last resort, kill all and try";
2792ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
2803ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        KillAllProcesses();
2812ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        // even if it succeeds, still it is timeout and do not run fsck with all processes killed
2822ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        UmountPartitions(0);
2832ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
2848d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2852ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park
2868d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
2872ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        // fsck part is excluded from timeout check. It only runs for user initiated shutdown
2882ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        // and should not affect reboot time.
2892ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        for (auto& entry : block_devices) {
2902ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park            entry.DoFsck();
2918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
2928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    return stat;
2948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
2958d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2968d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void __attribute__((noreturn)) DoThermalOff() {
2978d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    LOG(WARNING) << "Thermal system shutdown";
2982ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    sync();
2998d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    RebootSystem(ANDROID_RB_THERMOFF, "");
3008d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    abort();
3018d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
3028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkvoid DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
3048d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park              bool runFsck) {
3058d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    Timer t;
3063cd8c6f9123883d02e1c4c146e1ef7bfcfa170a3Keun-young Park    LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
3078d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3088d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE);
3098d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3108d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (cmd == ANDROID_RB_THERMOFF) {  // do not wait if it is thermal
3118d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        DoThermalOff();
3128d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        abort();
3138d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
314aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park
3153ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    /* TODO update default waiting time based on usage data */
316c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    constexpr unsigned int shutdownTimeoutDefault = 10;
317c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    unsigned int shutdownTimeout = shutdownTimeoutDefault;
318c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    if (SHUTDOWN_ZERO_TIMEOUT) {  // eng build
319c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park        shutdownTimeout = 0;
320c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    } else {
321c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park        shutdownTimeout =
322c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park            android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
323c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    }
324ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
325aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park
3267830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    // keep debugging tools until non critical ones are all gone.
3277830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
3287830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
3297830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    const std::set<std::string> to_starts{"watchdogd", "vold"};
3307830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
3317830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        if (kill_after_apps.count(s->name())) {
3327830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->SetShutdownCritical();
3337830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        } else if (to_starts.count(s->name())) {
3347830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->Start();
3357830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->SetShutdownCritical();
3368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
3377830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    });
3387830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park
3397830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
3407830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
3417830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
3427830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        property_set("service.bootanim.exit", "0");
3437830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        // Could be in the middle of animation. Stop and start so that it can pick
3447830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        // up the right mode.
3457830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        bootAnim->Stop();
3467830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        // start all animation classes if stopped.
3477830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
3487830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->Start();
3497830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->SetShutdownCritical();  // will not check animation class separately
3507830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        });
3517830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        bootAnim->Start();
3527830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        surfaceFlinger->SetShutdownCritical();
3537830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        bootAnim->SetShutdownCritical();
3548d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
3557830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park
3568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // optional shutdown step
3578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 1. terminate all services except shutdown critical ones. wait for delay to finish
3583ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    if (shutdownTimeout > 0) {
3598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(INFO) << "terminating init services";
3608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        // Ask all services to terminate except shutdown critical ones.
3628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        ServiceManager::GetInstance().ForEachService([](Service* s) {
3638d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            if (!s->IsShutdownCritical()) s->Terminate();
3648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        });
3658d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3668d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        int service_count = 0;
3673ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        // Up to half as long as shutdownTimeout or 3 seconds, whichever is lower.
3683ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        unsigned int terminationWaitTimeout = std::min<unsigned int>((shutdownTimeout + 1) / 2, 3);
3693ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        while (t.duration_s() < terminationWaitTimeout) {
3708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
3718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3728d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            service_count = 0;
3738d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
3748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // Count the number of services running except shutdown critical.
3758d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // Exclude the console as it will ignore the SIGTERM signal
3768d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // and not exit.
3778d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // Note: SVC_CONSOLE actually means "requires console" but
3788d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // it is only used by the shell.
3798d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
3808d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    service_count++;
3818d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                }
3828d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            });
3838d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3848d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            if (service_count == 0) {
3858d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // All terminable services terminated. We can exit early.
3868d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                break;
3878d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            }
3888d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3898d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            // Wait a bit before recounting the number or running services.
3908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            std::this_thread::sleep_for(50ms);
3918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
3928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(INFO) << "Terminating running services took " << t
3938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                  << " with remaining services:" << service_count;
3948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
3958d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3968d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // minimum safety steps before restarting
3978d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 2. kill all services except ones that are necessary for the shutdown sequence.
3982ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    ServiceManager::GetInstance().ForEachService([](Service* s) {
3992ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (!s->IsShutdownCritical()) s->Stop();
4008d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    });
4018d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
4028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
4038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 3. send volume shutdown to vold
4048d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
4058d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (voldService != nullptr && voldService->IsRunning()) {
4068d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        ShutdownVold();
4072ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        voldService->Stop();
4088d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    } else {
4098d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(INFO) << "vold not running, skipping vold shutdown";
4108d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
4112ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    // logcat stopped here
4122ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
4132ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park        if (kill_after_apps.count(s->name())) s->Stop();
4142ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    });
4158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 4. sync, try umount, and optionally run fsck for user shutdown
4162ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    sync();
4173ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
4182ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    // Follow what linux shutdown is doing: one more sync with little bit delay
4192ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    sync();
4202ba5c8103d0cf748fdf03c9e5be975ccc36fb56aKeun-young Park    std::this_thread::sleep_for(100ms);
4218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    LogShutdownTime(stat, &t);
4228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
4238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    RebootSystem(cmd, rebootTarget);
4248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    abort();
4258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
426