123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- #include "reboot.h"
- #include <dirent.h>
- #include <fcntl.h>
- #include <linux/fs.h>
- #include <mntent.h>
- #include <linux/loop.h>
- #include <sys/cdefs.h>
- #include <sys/ioctl.h>
- #include <sys/mount.h>
- #include <sys/swap.h>
- #include <sys/stat.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <memory>
- #include <set>
- #include <thread>
- #include <vector>
- #include <android-base/chrono_utils.h>
- #include <android-base/file.h>
- #include <android-base/logging.h>
- #include <android-base/macros.h>
- #include <android-base/properties.h>
- #include <android-base/stringprintf.h>
- #include <android-base/strings.h>
- #include <android-base/unique_fd.h>
- #include <bootloader_message/bootloader_message.h>
- #include <cutils/android_reboot.h>
- #include <fs_mgr.h>
- #include <logwrap/logwrap.h>
- #include <private/android_filesystem_config.h>
- #include <selinux/selinux.h>
- #include "action_manager.h"
- #include "init.h"
- #include "property_service.h"
- #include "reboot_utils.h"
- #include "service.h"
- #include "sigchld_handler.h"
- using android::base::GetBoolProperty;
- using android::base::Split;
- using android::base::StringPrintf;
- using android::base::Timer;
- using android::base::unique_fd;
- namespace android {
- namespace init {
- enum UmountStat {
-
- UMOUNT_STAT_SUCCESS = 0,
-
- UMOUNT_STAT_SKIPPED = 1,
-
- UMOUNT_STAT_TIMEOUT = 2,
-
- UMOUNT_STAT_ERROR = 3,
-
- UMOUNT_STAT_NOT_AVAILABLE = 4,
- };
- class MountEntry {
- public:
- explicit MountEntry(const mntent& entry)
- : mnt_fsname_(entry.mnt_fsname),
- mnt_dir_(entry.mnt_dir),
- mnt_type_(entry.mnt_type),
- mnt_opts_(entry.mnt_opts) {}
- bool Umount(bool force) {
- LOG(INFO) << "Unmounting " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
- int r = umount2(mnt_dir_.c_str(), force ? MNT_FORCE : 0);
- if (r == 0) {
- LOG(INFO) << "Umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
- return true;
- } else {
- PLOG(WARNING) << "Cannot umount " << mnt_fsname_ << ":" << mnt_dir_ << " opts "
- << mnt_opts_;
- return false;
- }
- }
- void DoFsck() {
- int st;
- if (IsF2Fs()) {
- const char* f2fs_argv[] = {
- "/system/bin/fsck.f2fs",
- "-a",
- mnt_fsname_.c_str(),
- };
- android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG,
- true, nullptr, nullptr, 0);
- } else if (IsExt4()) {
- const char* ext4_argv[] = {
- "/system/bin/e2fsck",
- "-y",
- mnt_fsname_.c_str(),
- };
- android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG,
- true, nullptr, nullptr, 0);
- }
- }
- static bool IsBlockDevice(const struct mntent& mntent) {
- return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
- }
- static bool IsEmulatedDevice(const struct mntent& mntent) {
- return android::base::StartsWith(mntent.mnt_fsname, "/data/");
- }
- private:
- bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
- bool IsExt4() const { return mnt_type_ == "ext4"; }
- std::string mnt_fsname_;
- std::string mnt_dir_;
- std::string mnt_type_;
- std::string mnt_opts_;
- };
- static void TurnOffBacklight() {
- Service* service = ServiceList::GetInstance().FindService("blank_screen");
- if (service == nullptr) {
- LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
- return;
- }
- if (auto result = service->Start(); !result) {
- LOG(WARNING) << "Could not start blank_screen service: " << result.error();
- }
- }
- 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().count()) << ":"
- << stat;
- }
- static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
- std::vector<MountEntry>* emulatedPartitions, bool dump) {
- std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
- if (fp == nullptr) {
- PLOG(ERROR) << "Failed to open /proc/mounts";
- return false;
- }
- mntent* mentry;
- while ((mentry = getmntent(fp.get())) != nullptr) {
- if (dump) {
- LOG(INFO) << "mount entry " << mentry->mnt_fsname << ":" << mentry->mnt_dir << " opts "
- << mentry->mnt_opts << " type " << mentry->mnt_type;
- } else if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
- std::string mount_dir(mentry->mnt_dir);
-
-
- if (mount_dir != "/" && mount_dir != "/system" && mount_dir != "/vendor" &&
- mount_dir != "/oem") {
- blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
- }
- } else if (MountEntry::IsEmulatedDevice(*mentry)) {
- emulatedPartitions->emplace(emulatedPartitions->begin(), *mentry);
- }
- }
- return true;
- }
- static void DumpUmountDebuggingInfo() {
- int status;
- if (!security_getenforce()) {
- LOG(INFO) << "Run lsof";
- const char* lsof_argv[] = {"/system/bin/lsof"};
- android_fork_execvp_ext(arraysize(lsof_argv), (char**)lsof_argv, &status, true, LOG_KLOG,
- true, nullptr, nullptr, 0);
- }
- FindPartitionsToUmount(nullptr, nullptr, true);
-
- android::base::WriteStringToFile("l", "/proc/sysrq-trigger");
- android::base::WriteStringToFile("w", "/proc/sysrq-trigger");
- }
- static UmountStat UmountPartitions(std::chrono::milliseconds timeout) {
- Timer t;
-
- while (true) {
- std::vector<MountEntry> block_devices;
- std::vector<MountEntry> emulated_devices;
- if (!FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
- return UMOUNT_STAT_ERROR;
- }
- if (block_devices.size() == 0) {
- return UMOUNT_STAT_SUCCESS;
- }
- bool unmount_done = true;
- if (emulated_devices.size() > 0) {
- for (auto& entry : emulated_devices) {
- if (!entry.Umount(false)) unmount_done = false;
- }
- if (unmount_done) {
- sync();
- }
- }
- for (auto& entry : block_devices) {
- if (!entry.Umount(timeout == 0ms)) unmount_done = false;
- }
- if (unmount_done) {
- return UMOUNT_STAT_SUCCESS;
- }
- if ((timeout < t.duration())) {
- return UMOUNT_STAT_TIMEOUT;
- }
- std::this_thread::sleep_for(100ms);
- }
- }
- static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
- static UmountStat TryUmountAndFsck(bool runFsck, std::chrono::milliseconds timeout) {
- Timer t;
- std::vector<MountEntry> block_devices;
- std::vector<MountEntry> emulated_devices;
- if (runFsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
- return UMOUNT_STAT_ERROR;
- }
- UmountStat stat = UmountPartitions(timeout - t.duration());
- if (stat != UMOUNT_STAT_SUCCESS) {
- LOG(INFO) << "umount timeout, last resort, kill all and try";
- if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
- KillAllProcesses();
-
- UmountStat st = UmountPartitions(0ms);
- if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
- }
- if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
-
-
- for (auto& entry : block_devices) {
- entry.DoFsck();
- }
- }
- return stat;
- }
- #define ZRAM_DEVICE "/dev/block/zram0"
- #define ZRAM_RESET "/sys/block/zram0/reset"
- #define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
- static void KillZramBackingDevice() {
- std::string backing_dev;
- if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return;
- if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return;
-
- backing_dev.erase(backing_dev.length() - 1);
-
- Timer swap_timer;
- LOG(INFO) << "swapoff() start...";
- if (swapoff(ZRAM_DEVICE) == -1) {
- LOG(ERROR) << "zram_backing_dev: swapoff (" << backing_dev << ")" << " failed";
- return;
- }
- LOG(INFO) << "swapoff() took " << swap_timer;;
- if (!android::base::WriteStringToFile("1", ZRAM_RESET)) {
- LOG(ERROR) << "zram_backing_dev: reset (" << backing_dev << ")" << " failed";
- return;
- }
-
- unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
- if (loop.get() < 0) {
- LOG(ERROR) << "zram_backing_dev: open(" << backing_dev << ")" << " failed";
- return;
- }
- if (ioctl(loop.get(), LOOP_CLR_FD, 0) < 0) {
- LOG(ERROR) << "zram_backing_dev: loop_clear (" << backing_dev << ")" << " failed";
- return;
- }
- LOG(INFO) << "zram_backing_dev: `" << backing_dev << "` is cleared successfully.";
- }
- static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
- bool runFsck) {
- Timer t;
- LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
-
-
- size_t skip = 0;
- std::vector<std::string> reasons = Split(reason, ",");
- if (reasons.size() >= 2 && reasons[0] == "reboot" &&
- (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
- reasons[1] == "hard" || reasons[1] == "warm")) {
- skip = strlen("reboot,");
- }
- property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
- sync();
- bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
- auto shutdown_timeout = 0ms;
- if (!SHUTDOWN_ZERO_TIMEOUT) {
- constexpr unsigned int shutdown_timeout_default = 6;
- constexpr unsigned int max_thermal_shutdown_timeout = 3;
- auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
- shutdown_timeout_default);
- if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
- shutdown_timeout_final = max_thermal_shutdown_timeout;
- }
- shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
- }
- LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
-
- const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
-
- const std::set<std::string> to_starts{"watchdogd"};
- for (const auto& s : ServiceList::GetInstance()) {
- if (kill_after_apps.count(s->name())) {
- s->SetShutdownCritical();
- } else if (to_starts.count(s->name())) {
- if (auto result = s->Start(); !result) {
- LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
- << "': " << result.error();
- }
- s->SetShutdownCritical();
- } else if (s->IsShutdownCritical()) {
-
- if (auto result = s->Start(); !result) {
- LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
- << "': " << result.error();
- }
- }
- }
-
- if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
- TurnOffBacklight();
- }
- Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
- Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
- if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
- bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false);
- if (do_shutdown_animation) {
- property_set("service.bootanim.exit", "0");
-
-
- bootAnim->Stop();
- }
- for (const auto& service : ServiceList::GetInstance()) {
- if (service->classnames().count("animation") == 0) {
- continue;
- }
-
- if (do_shutdown_animation) {
- service->Start().IgnoreError();
- }
- service->SetShutdownCritical();
- }
- if (do_shutdown_animation) {
- bootAnim->Start().IgnoreError();
- surfaceFlinger->SetShutdownCritical();
- bootAnim->SetShutdownCritical();
- }
- }
-
-
- if (shutdown_timeout > 0ms) {
- LOG(INFO) << "terminating init services";
-
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (!s->IsShutdownCritical()) s->Terminate();
- }
- int service_count = 0;
-
- auto termination_wait_timeout = shutdown_timeout / 2;
- while (t.duration() < termination_wait_timeout) {
- ReapAnyOutstandingChildren();
- service_count = 0;
- for (const auto& s : ServiceList::GetInstance()) {
-
-
-
-
-
- if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
- service_count++;
- }
- }
- if (service_count == 0) {
-
- break;
- }
-
- std::this_thread::sleep_for(50ms);
- }
- LOG(INFO) << "Terminating running services took " << t
- << " with remaining services:" << service_count;
- }
-
-
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (!s->IsShutdownCritical()) s->Stop();
- }
- SubcontextTerminate();
- ReapAnyOutstandingChildren();
-
- Service* voldService = ServiceList::GetInstance().FindService("vold");
- if (voldService != nullptr && voldService->IsRunning()) {
- ShutdownVold();
- voldService->Stop();
- } else {
- LOG(INFO) << "vold not running, skipping vold shutdown";
- }
-
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (kill_after_apps.count(s->name())) s->Stop();
- }
-
- {
- Timer sync_timer;
- LOG(INFO) << "sync() before umount...";
- sync();
- LOG(INFO) << "sync() before umount took" << sync_timer;
- }
-
- KillZramBackingDevice();
- UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
-
- {
- Timer sync_timer;
- LOG(INFO) << "sync() after umount...";
- sync();
- LOG(INFO) << "sync() after umount took" << sync_timer;
- }
- if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
- LogShutdownTime(stat, &t);
-
- RebootSystem(cmd, rebootTarget);
- abort();
- }
- bool HandlePowerctlMessage(const std::string& command) {
- unsigned int cmd = 0;
- std::vector<std::string> cmd_params = Split(command, ",");
- std::string reboot_target = "";
- bool run_fsck = false;
- bool command_invalid = false;
- if (cmd_params.size() > 3) {
- command_invalid = true;
- } else if (cmd_params[0] == "shutdown") {
- cmd = ANDROID_RB_POWEROFF;
- if (cmd_params.size() == 2) {
- if (cmd_params[1] == "userrequested") {
-
-
- run_fsck = true;
- } else if (cmd_params[1] == "thermal") {
-
- TurnOffBacklight();
-
- cmd = ANDROID_RB_THERMOFF;
- }
- }
- } else if (cmd_params[0] == "reboot") {
- cmd = ANDROID_RB_RESTART2;
- if (cmd_params.size() >= 2) {
- reboot_target = cmd_params[1];
-
-
- if (reboot_target == "fastboot" &&
- !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
- reboot_target = "bootloader";
- }
-
-
- if (reboot_target == "bootloader") {
- std::string err;
- if (!write_reboot_bootloader(&err)) {
- LOG(ERROR) << "reboot-bootloader: Error writing "
- "bootloader_message: "
- << err;
- }
- } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
- reboot_target == "fastboot") {
- std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
- : reboot_target;
- const std::vector<std::string> options = {
- "--" + arg,
- };
- std::string err;
- if (!write_bootloader_message(options, &err)) {
- LOG(ERROR) << "Failed to set bootloader message: " << err;
- return false;
- }
- reboot_target = "recovery";
- }
-
- if ((cmd_params.size() == 3) && cmd_params[2].size()) {
- reboot_target += "," + cmd_params[2];
- }
- }
- } else {
- command_invalid = true;
- }
- if (command_invalid) {
- LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
- return false;
- }
- LOG(INFO) << "Clear action queue and start shutdown trigger";
- ActionManager::GetInstance().ClearQueue();
-
- ActionManager::GetInstance().QueueEventTrigger("shutdown");
-
- auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
- DoReboot(cmd, command, reboot_target, run_fsck);
- return Success();
- };
- ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
-
- ResetWaitForProp();
-
- for (const auto& s : ServiceList::GetInstance()) {
- s->UnSetExec();
- }
- return true;
- }
- }
- }
|