reboot.cpp revision 3f5eaae526413a29de899270714469c76dc91ec8
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "reboot.h"
18
19#include <dirent.h>
20#include <fcntl.h>
21#include <mntent.h>
22#include <sys/cdefs.h>
23#include <sys/mount.h>
24#include <sys/quota.h>
25#include <sys/reboot.h>
26#include <sys/stat.h>
27#include <sys/syscall.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30
31#include <memory>
32#include <set>
33#include <thread>
34#include <vector>
35
36#include <android-base/file.h>
37#include <android-base/logging.h>
38#include <android-base/macros.h>
39#include <android-base/properties.h>
40#include <android-base/stringprintf.h>
41#include <android-base/strings.h>
42#include <bootloader_message/bootloader_message.h>
43#include <cutils/android_reboot.h>
44#include <fs_mgr.h>
45#include <logwrap/logwrap.h>
46
47#include "property_service.h"
48#include "service.h"
49
50using android::base::StringPrintf;
51
52// represents umount status during reboot / shutdown.
53enum UmountStat {
54    /* umount succeeded. */
55    UMOUNT_STAT_SUCCESS = 0,
56    /* umount was not run. */
57    UMOUNT_STAT_SKIPPED = 1,
58    /* umount failed with timeout. */
59    UMOUNT_STAT_TIMEOUT = 2,
60    /* could not run due to error */
61    UMOUNT_STAT_ERROR = 3,
62    /* not used by init but reserved for other part to use this to represent the
63       the state where umount status before reboot is not found / available. */
64    UMOUNT_STAT_NOT_AVAILABLE = 4,
65};
66
67// Utility for struct mntent
68class MountEntry {
69  public:
70    explicit MountEntry(const mntent& entry, bool isMounted = true)
71        : mnt_fsname_(entry.mnt_fsname),
72          mnt_dir_(entry.mnt_dir),
73          mnt_type_(entry.mnt_type),
74          is_mounted_(isMounted) {}
75
76    bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
77
78    bool IsExt4() const { return mnt_type_ == "ext4"; }
79
80    bool is_mounted() const { return is_mounted_; }
81
82    void set_is_mounted() { is_mounted_ = false; }
83
84    const std::string& mnt_fsname() const { return mnt_fsname_; }
85
86    const std::string& mnt_dir() const { return mnt_dir_; }
87
88    static bool IsBlockDevice(const struct mntent& mntent) {
89        return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
90    }
91
92    static bool IsEmulatedDevice(const struct mntent& mntent) {
93        static const std::string SDCARDFS_NAME = "sdcardfs";
94        return android::base::StartsWith(mntent.mnt_fsname, "/data/") &&
95               SDCARDFS_NAME == mntent.mnt_type;
96    }
97
98  private:
99    std::string mnt_fsname_;
100    std::string mnt_dir_;
101    std::string mnt_type_;
102    bool is_mounted_;
103};
104
105// Turn off backlight while we are performing power down cleanup activities.
106static void TurnOffBacklight() {
107    static constexpr char OFF[] = "0";
108
109    android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
110
111    static const char backlightDir[] = "/sys/class/backlight";
112    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
113    if (!dir) {
114        return;
115    }
116
117    struct dirent* dp;
118    while ((dp = readdir(dir.get())) != nullptr) {
119        if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
120            continue;
121        }
122
123        std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
124        android::base::WriteStringToFile(OFF, fileName);
125    }
126}
127
128static void DoFsck(const MountEntry& entry) {
129    static constexpr int UNMOUNT_CHECK_TIMES = 10;
130
131    if (!entry.IsF2Fs() && !entry.IsExt4()) return;
132
133    int count = 0;
134    while (count++ < UNMOUNT_CHECK_TIMES) {
135        int fd = TEMP_FAILURE_RETRY(open(entry.mnt_fsname().c_str(), O_RDONLY | O_EXCL));
136        if (fd >= 0) {
137            /* |entry->mnt_dir| has sucessfully been unmounted. */
138            close(fd);
139            break;
140        } else if (errno == EBUSY) {
141            // Some processes using |entry->mnt_dir| are still alive. Wait for a
142            // while then retry.
143            std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
144            continue;
145        } else {
146            /* Cannot open the device. Give up. */
147            return;
148        }
149    }
150
151    // NB: With watchdog still running, there is no cap on the time it takes
152    // to complete the fsck, from the users perspective the device graphics
153    // and responses are locked-up and they may choose to hold the power
154    // button in frustration if it drags out.
155
156    int st;
157    if (entry.IsF2Fs()) {
158        const char* f2fs_argv[] = {
159            "/system/bin/fsck.f2fs", "-f", entry.mnt_fsname().c_str(),
160        };
161        android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG, true,
162                                nullptr, nullptr, 0);
163    } else if (entry.IsExt4()) {
164        const char* ext4_argv[] = {
165            "/system/bin/e2fsck", "-f", "-y", entry.mnt_fsname().c_str(),
166        };
167        android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG, true,
168                                nullptr, nullptr, 0);
169    }
170}
171
172static void ShutdownVold() {
173    const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
174    int status;
175    android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true, LOG_KLOG, true,
176                            nullptr, nullptr, 0);
177}
178
179static void LogShutdownTime(UmountStat stat, Timer* t) {
180    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
181}
182
183static void __attribute__((noreturn))
184RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
185    LOG(INFO) << "Reboot ending, jumping to kernel";
186    switch (cmd) {
187        case ANDROID_RB_POWEROFF:
188            reboot(RB_POWER_OFF);
189            break;
190
191        case ANDROID_RB_RESTART2:
192            syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
193                    LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
194            break;
195
196        case ANDROID_RB_THERMOFF:
197            reboot(RB_POWER_OFF);
198            break;
199    }
200    // In normal case, reboot should not return.
201    PLOG(FATAL) << "reboot call returned";
202    abort();
203}
204
205static void DoSync() {
206    // quota sync is not done by sync call, so should be done separately.
207    // quota sync is in VFS level, so do it before sync, which goes down to fs level.
208    int r = quotactl(QCMD(Q_SYNC, 0), nullptr, 0 /* do not care */, 0 /* do not care */);
209    if (r < 0) {
210        PLOG(ERROR) << "quotactl failed";
211    }
212    sync();
213}
214
215/* Find all read+write block devices and emulated devices in /proc/mounts
216 * and add them to correpsponding list.
217 */
218static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
219                                   std::vector<MountEntry>* emulatedPartitions) {
220    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
221    if (fp == nullptr) {
222        PLOG(ERROR) << "Failed to open /proc/mounts";
223        return false;
224    }
225    mntent* mentry;
226    while ((mentry = getmntent(fp.get())) != nullptr) {
227        if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
228            blockDevPartitions->emplace_back(*mentry);
229        } else if (MountEntry::IsEmulatedDevice(*mentry)) {
230            emulatedPartitions->emplace_back(*mentry);
231        }
232    }
233    return true;
234}
235
236static bool UmountPartitions(std::vector<MountEntry>* partitions, int maxRetry, int flags) {
237    static constexpr int SLEEP_AFTER_RETRY_US = 100000;
238
239    bool umountDone;
240    int retryCounter = 0;
241
242    while (true) {
243        umountDone = true;
244        for (auto& entry : *partitions) {
245            if (entry.is_mounted()) {
246                int r = umount2(entry.mnt_dir().c_str(), flags);
247                if (r == 0) {
248                    entry.set_is_mounted();
249                    LOG(INFO) << StringPrintf("umounted %s, flags:0x%x", entry.mnt_fsname().c_str(),
250                                              flags);
251                } else {
252                    umountDone = false;
253                    PLOG(WARNING) << StringPrintf("cannot umount %s, mnt_dir %s, flags:0x%x",
254                                                  entry.mnt_fsname().c_str(),
255                                                  entry.mnt_dir().c_str(), flags);
256                }
257            }
258        }
259        if (umountDone) break;
260        retryCounter++;
261        if (retryCounter >= maxRetry) break;
262        usleep(SLEEP_AFTER_RETRY_US);
263    }
264    return umountDone;
265}
266
267static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
268
269/* Try umounting all emulated file systems R/W block device cfile systems.
270 * This will just try umount and give it up if it fails.
271 * For fs like ext4, this is ok as file system will be marked as unclean shutdown
272 * and necessary check can be done at the next reboot.
273 * For safer shutdown, caller needs to make sure that
274 * all processes / emulated partition for the target fs are all cleaned-up.
275 *
276 * return true when umount was successful. false when timed out.
277 */
278static UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
279    Timer t;
280    std::vector<MountEntry> emulatedPartitions;
281    std::vector<MountEntry> blockDevRwPartitions;
282
283    TurnOffBacklight();  // this part can take time. save power.
284
285    if (!FindPartitionsToUmount(&blockDevRwPartitions, &emulatedPartitions)) {
286        return UMOUNT_STAT_ERROR;
287    }
288    if (emulatedPartitions.size() > 0) {
289        LOG(WARNING) << "emulated partitions still exist, will umount";
290        /* Pending writes in emulated partitions can fail umount. After a few trials, detach
291         * it so that it can be umounted when all writes are done.
292         */
293        if (!UmountPartitions(&emulatedPartitions, 1, 0)) {
294            UmountPartitions(&emulatedPartitions, 1, MNT_DETACH);
295        }
296    }
297    DoSync();  // emulated partition change can lead to update
298    UmountStat stat = UMOUNT_STAT_SUCCESS;
299    /* data partition needs all pending writes to be completed and all emulated partitions
300     * umounted. If umount failed in the above step, it DETACH is requested, so umount can
301     * still happen while waiting for /data. If the current waiting is not good enough, give
302     * up and leave it to e2fsck after reboot to fix it.
303     */
304    int remainingTimeMs = timeoutMs - t.duration_ms();
305    // each retry takes 100ms, and run at least once.
306    int retry = std::max(remainingTimeMs / 100, 1);
307    if (!UmountPartitions(&blockDevRwPartitions, retry, 0)) {
308        /* Last resort, kill all and try again */
309        LOG(WARNING) << "umount still failing, trying kill all";
310        KillAllProcesses();
311        DoSync();
312        if (!UmountPartitions(&blockDevRwPartitions, 1, 0)) {
313            stat = UMOUNT_STAT_TIMEOUT;
314        }
315    }
316    // fsck part is excluded from timeout check. It only runs for user initiated shutdown
317    // and should not affect reboot time.
318    if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
319        for (auto& entry : blockDevRwPartitions) {
320            DoFsck(entry);
321        }
322    }
323
324    return stat;
325}
326
327static void __attribute__((noreturn)) DoThermalOff() {
328    LOG(WARNING) << "Thermal system shutdown";
329    DoSync();
330    RebootSystem(ANDROID_RB_THERMOFF, "");
331    abort();
332}
333
334void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
335              bool runFsck) {
336    Timer t;
337    LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
338
339    android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE);
340
341    if (cmd == ANDROID_RB_THERMOFF) {  // do not wait if it is thermal
342        DoThermalOff();
343        abort();
344    }
345
346    /* TODO update default waiting time based on usage data */
347    constexpr unsigned int shutdownTimeoutDefault = 10;
348    unsigned int shutdownTimeout = shutdownTimeoutDefault;
349    if (SHUTDOWN_ZERO_TIMEOUT) {  // eng build
350        shutdownTimeout = 0;
351    } else {
352        shutdownTimeout =
353            android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
354    }
355    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
356
357    // keep debugging tools until non critical ones are all gone.
358    const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
359    // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
360    const std::set<std::string> to_starts{"watchdogd", "vold"};
361    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
362        if (kill_after_apps.count(s->name())) {
363            s->SetShutdownCritical();
364        } else if (to_starts.count(s->name())) {
365            s->Start();
366            s->SetShutdownCritical();
367        }
368    });
369
370    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
371    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
372    if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
373        property_set("service.bootanim.exit", "0");
374        // Could be in the middle of animation. Stop and start so that it can pick
375        // up the right mode.
376        bootAnim->Stop();
377        // start all animation classes if stopped.
378        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
379            s->Start();
380            s->SetShutdownCritical();  // will not check animation class separately
381        });
382        bootAnim->Start();
383        surfaceFlinger->SetShutdownCritical();
384        bootAnim->SetShutdownCritical();
385    }
386
387    // optional shutdown step
388    // 1. terminate all services except shutdown critical ones. wait for delay to finish
389    if (shutdownTimeout > 0) {
390        LOG(INFO) << "terminating init services";
391
392        // Ask all services to terminate except shutdown critical ones.
393        ServiceManager::GetInstance().ForEachService([](Service* s) {
394            if (!s->IsShutdownCritical()) s->Terminate();
395        });
396
397        int service_count = 0;
398        // Up to half as long as shutdownTimeout or 3 seconds, whichever is lower.
399        unsigned int terminationWaitTimeout = std::min<unsigned int>((shutdownTimeout + 1) / 2, 3);
400        while (t.duration_s() < terminationWaitTimeout) {
401            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
402
403            service_count = 0;
404            ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
405                // Count the number of services running except shutdown critical.
406                // Exclude the console as it will ignore the SIGTERM signal
407                // and not exit.
408                // Note: SVC_CONSOLE actually means "requires console" but
409                // it is only used by the shell.
410                if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
411                    service_count++;
412                }
413            });
414
415            if (service_count == 0) {
416                // All terminable services terminated. We can exit early.
417                break;
418            }
419
420            // Wait a bit before recounting the number or running services.
421            std::this_thread::sleep_for(50ms);
422        }
423        LOG(INFO) << "Terminating running services took " << t
424                  << " with remaining services:" << service_count;
425    }
426
427    // minimum safety steps before restarting
428    // 2. kill all services except ones that are necessary for the shutdown sequence.
429    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
430        if (!s->IsShutdownCritical() || kill_after_apps.count(s->name())) s->Stop();
431    });
432    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
433
434    // 3. send volume shutdown to vold
435    Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
436    if (voldService != nullptr && voldService->IsRunning()) {
437        ShutdownVold();
438    } else {
439        LOG(INFO) << "vold not running, skipping vold shutdown";
440    }
441    // 4. sync, try umount, and optionally run fsck for user shutdown
442    DoSync();
443    UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
444    LogShutdownTime(stat, &t);
445    // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
446    RebootSystem(cmd, rebootTarget);
447    abort();
448}
449