reboot.cpp revision 3f5eaae526413a29de899270714469c76dc91ec8
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>
218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <mntent.h>
228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/cdefs.h>
238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/mount.h>
248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/quota.h>
258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/reboot.h>
268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/stat.h>
278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/syscall.h>
288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/types.h>
298d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <sys/wait.h>
308d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <memory>
327830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park#include <set>
338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <thread>
348d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <vector>
358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/file.h>
373f5eaae526413a29de899270714469c76dc91ec8Tom Cherry#include <android-base/logging.h>
388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/macros.h>
39ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/properties.h>
408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/stringprintf.h>
418d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <android-base/strings.h>
428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <bootloader_message/bootloader_message.h>
438d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <cutils/android_reboot.h>
448d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <fs_mgr.h>
458d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include <logwrap/logwrap.h>
468d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
477830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park#include "property_service.h"
488d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park#include "service.h"
498d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
508d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkusing android::base::StringPrintf;
518d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
528d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park// represents umount status during reboot / shutdown.
538d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkenum UmountStat {
548d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* umount succeeded. */
558d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_SUCCESS = 0,
568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* umount was not run. */
578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_SKIPPED = 1,
588d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* umount failed with timeout. */
598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_TIMEOUT = 2,
608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* could not run due to error */
618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_ERROR = 3,
628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* not used by init but reserved for other part to use this to represent the
638d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park       the state where umount status before reboot is not found / available. */
648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UMOUNT_STAT_NOT_AVAILABLE = 4,
658d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park};
668d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
678d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park// Utility for struct mntent
688d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkclass MountEntry {
698d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park  public:
708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    explicit MountEntry(const mntent& entry, bool isMounted = true)
718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        : mnt_fsname_(entry.mnt_fsname),
728d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park          mnt_dir_(entry.mnt_dir),
738d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park          mnt_type_(entry.mnt_type),
748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park          is_mounted_(isMounted) {}
758d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
768d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
778d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
788d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    bool IsExt4() const { return mnt_type_ == "ext4"; }
798d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
808d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    bool is_mounted() const { return is_mounted_; }
818d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
828d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    void set_is_mounted() { is_mounted_ = false; }
838d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
848d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    const std::string& mnt_fsname() const { return mnt_fsname_; }
858d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
868d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    const std::string& mnt_dir() const { return mnt_dir_; }
878d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
888d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static bool IsBlockDevice(const struct mntent& mntent) {
898d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static bool IsEmulatedDevice(const struct mntent& mntent) {
938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        static const std::string SDCARDFS_NAME = "sdcardfs";
948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return android::base::StartsWith(mntent.mnt_fsname, "/data/") &&
958d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park               SDCARDFS_NAME == mntent.mnt_type;
968d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
978d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
988d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park  private:
998d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::string mnt_fsname_;
1008d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::string mnt_dir_;
1018d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::string mnt_type_;
1028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    bool is_mounted_;
1038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park};
1048d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1058d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park// Turn off backlight while we are performing power down cleanup activities.
1068d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void TurnOffBacklight() {
1078d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static constexpr char OFF[] = "0";
1088d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1098d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
1108d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1118d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static const char backlightDir[] = "/sys/class/backlight";
1128d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
1138d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (!dir) {
1148d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return;
1158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1168d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1178d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    struct dirent* dp;
1188d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while ((dp = readdir(dir.get())) != nullptr) {
1198d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
1208d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            continue;
1218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
1228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
1248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        android::base::WriteStringToFile(OFF, fileName);
1258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void DoFsck(const MountEntry& entry) {
1298d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static constexpr int UNMOUNT_CHECK_TIMES = 10;
1308d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (!entry.IsF2Fs() && !entry.IsExt4()) return;
1328d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    int count = 0;
1348d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while (count++ < UNMOUNT_CHECK_TIMES) {
1358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        int fd = TEMP_FAILURE_RETRY(open(entry.mnt_fsname().c_str(), O_RDONLY | O_EXCL));
1368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (fd >= 0) {
1378d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            /* |entry->mnt_dir| has sucessfully been unmounted. */
1388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            close(fd);
1398d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        } else if (errno == EBUSY) {
1418d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            // Some processes using |entry->mnt_dir| are still alive. Wait for a
1428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            // while then retry.
1438d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
1448d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            continue;
1458d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        } else {
1468d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            /* Cannot open the device. Give up. */
1478d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            return;
1488d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
1498d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1508d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1518d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // NB: With watchdog still running, there is no cap on the time it takes
1528d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // to complete the fsck, from the users perspective the device graphics
1538d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // and responses are locked-up and they may choose to hold the power
1548d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // button in frustration if it drags out.
1558d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    int st;
1578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (entry.IsF2Fs()) {
1588d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        const char* f2fs_argv[] = {
1598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            "/system/bin/fsck.f2fs", "-f", entry.mnt_fsname().c_str(),
1608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        };
1618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG, true,
1628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                                nullptr, nullptr, 0);
1638d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    } else if (entry.IsExt4()) {
1648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        const char* ext4_argv[] = {
1658d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            "/system/bin/e2fsck", "-f", "-y", entry.mnt_fsname().c_str(),
1668d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        };
1678d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG, true,
1688d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                                nullptr, nullptr, 0);
1698d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
1708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1728d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void ShutdownVold() {
1738d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
1748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    int status;
1758d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true, LOG_KLOG, true,
1768d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                            nullptr, nullptr, 0);
1778d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1788d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1798d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void LogShutdownTime(UmountStat stat, Timer* t) {
1808d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
1818d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
1828d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1838d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void __attribute__((noreturn))
1848d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young ParkRebootSystem(unsigned int cmd, const std::string& rebootTarget) {
1853cd8c6f9123883d02e1c4c146e1ef7bfcfa170a3Keun-young Park    LOG(INFO) << "Reboot ending, jumping to kernel";
1868d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    switch (cmd) {
1878d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        case ANDROID_RB_POWEROFF:
1888d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            reboot(RB_POWER_OFF);
1898d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        case ANDROID_RB_RESTART2:
1928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
1938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
1948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1958d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
1968d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        case ANDROID_RB_THERMOFF:
1978d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            reboot(RB_POWER_OFF);
1988d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            break;
1998d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2008d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // In normal case, reboot should not return.
2018d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    PLOG(FATAL) << "reboot call returned";
2028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    abort();
2038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
2048d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
205aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Parkstatic void DoSync() {
206aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    // quota sync is not done by sync call, so should be done separately.
207aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    // quota sync is in VFS level, so do it before sync, which goes down to fs level.
208aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    int r = quotactl(QCMD(Q_SYNC, 0), nullptr, 0 /* do not care */, 0 /* do not care */);
209aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    if (r < 0) {
210aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park        PLOG(ERROR) << "quotactl failed";
211aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    }
212aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    sync();
213aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park}
214aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park
2158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park/* Find all read+write block devices and emulated devices in /proc/mounts
2168d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * and add them to correpsponding list.
2178d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park */
2188d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
2198d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                                   std::vector<MountEntry>* emulatedPartitions) {
2208d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
2218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (fp == nullptr) {
2228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        PLOG(ERROR) << "Failed to open /proc/mounts";
2238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return false;
2248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    mntent* mentry;
2268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while ((mentry = getmntent(fp.get())) != nullptr) {
2278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
2288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            blockDevPartitions->emplace_back(*mentry);
2298d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        } else if (MountEntry::IsEmulatedDevice(*mentry)) {
2308d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            emulatedPartitions->emplace_back(*mentry);
2318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
2328d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    return true;
2348d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
2358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic bool UmountPartitions(std::vector<MountEntry>* partitions, int maxRetry, int flags) {
2378d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    static constexpr int SLEEP_AFTER_RETRY_US = 100000;
2388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2398d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    bool umountDone;
2408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    int retryCounter = 0;
2418d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    while (true) {
2438d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        umountDone = true;
2448d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        for (auto& entry : *partitions) {
2458d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            if (entry.is_mounted()) {
2468d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                int r = umount2(entry.mnt_dir().c_str(), flags);
2478d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                if (r == 0) {
2488d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    entry.set_is_mounted();
2498d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    LOG(INFO) << StringPrintf("umounted %s, flags:0x%x", entry.mnt_fsname().c_str(),
2508d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                                              flags);
2518d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                } else {
2528d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    umountDone = false;
2537830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park                    PLOG(WARNING) << StringPrintf("cannot umount %s, mnt_dir %s, flags:0x%x",
2547830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park                                                  entry.mnt_fsname().c_str(),
2557830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park                                                  entry.mnt_dir().c_str(), flags);
2568d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                }
2578d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            }
2588d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
2598d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (umountDone) break;
2608d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        retryCounter++;
2618d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (retryCounter >= maxRetry) break;
2628d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        usleep(SLEEP_AFTER_RETRY_US);
2638d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2648d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    return umountDone;
2658d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
2668d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2673ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Parkstatic void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
2683ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park
2698d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park/* Try umounting all emulated file systems R/W block device cfile systems.
2708d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * This will just try umount and give it up if it fails.
2718d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * For fs like ext4, this is ok as file system will be marked as unclean shutdown
2728d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * and necessary check can be done at the next reboot.
2738d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * For safer shutdown, caller needs to make sure that
2748d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * all processes / emulated partition for the target fs are all cleaned-up.
2758d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park *
2768d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park * return true when umount was successful. false when timed out.
2778d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park */
2783ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Parkstatic UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
2793ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    Timer t;
2808d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::vector<MountEntry> emulatedPartitions;
2818d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    std::vector<MountEntry> blockDevRwPartitions;
2828d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2838d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    TurnOffBacklight();  // this part can take time. save power.
2848d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
2858d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (!FindPartitionsToUmount(&blockDevRwPartitions, &emulatedPartitions)) {
2868d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        return UMOUNT_STAT_ERROR;
2878d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
2888d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (emulatedPartitions.size() > 0) {
2898d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(WARNING) << "emulated partitions still exist, will umount";
2908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        /* Pending writes in emulated partitions can fail umount. After a few trials, detach
2918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park         * it so that it can be umounted when all writes are done.
2928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park         */
2938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        if (!UmountPartitions(&emulatedPartitions, 1, 0)) {
2948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            UmountPartitions(&emulatedPartitions, 1, MNT_DETACH);
2958d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
2968d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
297aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park    DoSync();  // emulated partition change can lead to update
2988d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    UmountStat stat = UMOUNT_STAT_SUCCESS;
2998d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    /* data partition needs all pending writes to be completed and all emulated partitions
3008d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park     * umounted. If umount failed in the above step, it DETACH is requested, so umount can
3018d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park     * still happen while waiting for /data. If the current waiting is not good enough, give
3028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park     * up and leave it to e2fsck after reboot to fix it.
3038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park     */
3043ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    int remainingTimeMs = timeoutMs - t.duration_ms();
3053ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    // each retry takes 100ms, and run at least once.
3063ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    int retry = std::max(remainingTimeMs / 100, 1);
3073ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    if (!UmountPartitions(&blockDevRwPartitions, retry, 0)) {
3083ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        /* Last resort, kill all and try again */
3093ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        LOG(WARNING) << "umount still failing, trying kill all";
3103ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        KillAllProcesses();
3113ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        DoSync();
3123ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        if (!UmountPartitions(&blockDevRwPartitions, 1, 0)) {
3133ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park            stat = UMOUNT_STAT_TIMEOUT;
3143ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        }
3158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
3163ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    // fsck part is excluded from timeout check. It only runs for user initiated shutdown
3173ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    // and should not affect reboot time.
3188d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
3198d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        for (auto& entry : blockDevRwPartitions) {
3208d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            DoFsck(entry);
3218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
3228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
3238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    return stat;
3258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
3268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkstatic void __attribute__((noreturn)) DoThermalOff() {
3288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    LOG(WARNING) << "Thermal system shutdown";
3298d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    DoSync();
3308d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    RebootSystem(ANDROID_RB_THERMOFF, "");
3318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    abort();
3328d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
3338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3348d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Parkvoid DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
3358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park              bool runFsck) {
3368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    Timer t;
3373cd8c6f9123883d02e1c4c146e1ef7bfcfa170a3Keun-young Park    LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
3388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3398d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE);
3408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3418d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (cmd == ANDROID_RB_THERMOFF) {  // do not wait if it is thermal
3428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        DoThermalOff();
3438d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        abort();
3448d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
345aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park
3463ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    /* TODO update default waiting time based on usage data */
347c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    constexpr unsigned int shutdownTimeoutDefault = 10;
348c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    unsigned int shutdownTimeout = shutdownTimeoutDefault;
349c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    if (SHUTDOWN_ZERO_TIMEOUT) {  // eng build
350c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park        shutdownTimeout = 0;
351c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    } else {
352c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park        shutdownTimeout =
353c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park            android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
354c4ffa5c47d0ac84cae57337412c2459f2cb11da5Keun-young Park    }
355ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
356aa08ea458a3aea9f671f847f4e005c3bd39da201Keun-young Park
3577830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    // keep debugging tools until non critical ones are all gone.
3587830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
3597830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
3607830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    const std::set<std::string> to_starts{"watchdogd", "vold"};
3617830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
3627830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        if (kill_after_apps.count(s->name())) {
3637830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->SetShutdownCritical();
3647830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        } else if (to_starts.count(s->name())) {
3657830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->Start();
3667830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->SetShutdownCritical();
3678d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
3687830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    });
3697830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park
3707830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
3717830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
3727830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
3737830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        property_set("service.bootanim.exit", "0");
3747830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        // Could be in the middle of animation. Stop and start so that it can pick
3757830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        // up the right mode.
3767830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        bootAnim->Stop();
3777830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        // start all animation classes if stopped.
3787830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
3797830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->Start();
3807830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park            s->SetShutdownCritical();  // will not check animation class separately
3817830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        });
3827830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        bootAnim->Start();
3837830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        surfaceFlinger->SetShutdownCritical();
3847830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        bootAnim->SetShutdownCritical();
3858d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
3867830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park
3878d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // optional shutdown step
3888d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 1. terminate all services except shutdown critical ones. wait for delay to finish
3893ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    if (shutdownTimeout > 0) {
3908d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(INFO) << "terminating init services";
3918d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3928d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        // Ask all services to terminate except shutdown critical ones.
3938d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        ServiceManager::GetInstance().ForEachService([](Service* s) {
3948d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            if (!s->IsShutdownCritical()) s->Terminate();
3958d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        });
3968d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
3978d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        int service_count = 0;
3983ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        // Up to half as long as shutdownTimeout or 3 seconds, whichever is lower.
3993ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        unsigned int terminationWaitTimeout = std::min<unsigned int>((shutdownTimeout + 1) / 2, 3);
4003ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park        while (t.duration_s() < terminationWaitTimeout) {
4018d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
4028d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
4038d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            service_count = 0;
4048d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
4058d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // Count the number of services running except shutdown critical.
4068d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // Exclude the console as it will ignore the SIGTERM signal
4078d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // and not exit.
4088d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // Note: SVC_CONSOLE actually means "requires console" but
4098d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // it is only used by the shell.
4108d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
4118d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                    service_count++;
4128d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                }
4138d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            });
4148d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
4158d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            if (service_count == 0) {
4168d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                // All terminable services terminated. We can exit early.
4178d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                break;
4188d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            }
4198d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
4208d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            // Wait a bit before recounting the number or running services.
4218d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park            std::this_thread::sleep_for(50ms);
4228d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        }
4238d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(INFO) << "Terminating running services took " << t
4248d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park                  << " with remaining services:" << service_count;
4258d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
4268d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
4278d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // minimum safety steps before restarting
4288d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 2. kill all services except ones that are necessary for the shutdown sequence.
4297830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
4307830d59500eb0cb24333dc357ac5bed38270e181Keun-young Park        if (!s->IsShutdownCritical() || kill_after_apps.count(s->name())) s->Stop();
4318d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    });
4328d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
4338d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park
4348d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 3. send volume shutdown to vold
4358d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
4368d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    if (voldService != nullptr && voldService->IsRunning()) {
4378d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        ShutdownVold();
4388d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    } else {
4398d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park        LOG(INFO) << "vold not running, skipping vold shutdown";
4408d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    }
4418d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // 4. sync, try umount, and optionally run fsck for user shutdown
4428d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    DoSync();
4433ee0df9bdfef5e872d278b3d4d073a379ca62451Keun-young Park    UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
4448d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    LogShutdownTime(stat, &t);
4458d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
4468d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    RebootSystem(cmd, rebootTarget);
4478d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park    abort();
4488d01f63f50fb001f41835a0dab636981f2ba76ddKeun-young Park}
449