• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <dirent.h>
17 #include <fcntl.h>
18 #include <linux/fs.h>
19 #include <mntent.h>
20 #include <selinux/selinux.h>
21 #include <sys/cdefs.h>
22 #include <sys/ioctl.h>
23 #include <sys/mount.h>
24 #include <sys/reboot.h>
25 #include <sys/stat.h>
26 #include <sys/syscall.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 
30 #include <memory>
31 #include <set>
32 #include <string>
33 #include <thread>
34 #include <vector>
35 
36 #include <android-base/file.h>
37 #include <android-base/macros.h>
38 #include <android-base/properties.h>
39 #include <android-base/stringprintf.h>
40 #include <android-base/strings.h>
41 #include <android-base/unique_fd.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 #include <private/android_filesystem_config.h>
47 
48 #include "log.h"
49 #include "property_service.h"
50 #include "reboot.h"
51 #include "service.h"
52 #include "util.h"
53 
54 using android::base::StringPrintf;
55 
56 // represents umount status during reboot / shutdown.
57 enum UmountStat {
58     /* umount succeeded. */
59     UMOUNT_STAT_SUCCESS = 0,
60     /* umount was not run. */
61     UMOUNT_STAT_SKIPPED = 1,
62     /* umount failed with timeout. */
63     UMOUNT_STAT_TIMEOUT = 2,
64     /* could not run due to error */
65     UMOUNT_STAT_ERROR = 3,
66     /* not used by init but reserved for other part to use this to represent the
67        the state where umount status before reboot is not found / available. */
68     UMOUNT_STAT_NOT_AVAILABLE = 4,
69 };
70 
71 // Utility for struct mntent
72 class MountEntry {
73   public:
MountEntry(const mntent & entry)74     explicit MountEntry(const mntent& entry)
75         : mnt_fsname_(entry.mnt_fsname),
76           mnt_dir_(entry.mnt_dir),
77           mnt_type_(entry.mnt_type),
78           mnt_opts_(entry.mnt_opts) {}
79 
Umount()80     bool Umount() {
81         int r = umount2(mnt_dir_.c_str(), 0);
82         if (r == 0) {
83             LOG(INFO) << "umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
84             return true;
85         } else {
86             PLOG(WARNING) << "cannot umount " << mnt_fsname_ << ":" << mnt_dir_ << " opts "
87                           << mnt_opts_;
88             return false;
89         }
90     }
91 
DoFsck()92     void DoFsck() {
93         int st;
94         if (IsF2Fs()) {
95             const char* f2fs_argv[] = {
96                 "/system/bin/fsck.f2fs", "-f", mnt_fsname_.c_str(),
97             };
98             android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG,
99                                     true, nullptr, nullptr, 0);
100         } else if (IsExt4()) {
101             const char* ext4_argv[] = {
102                 "/system/bin/e2fsck", "-f", "-y", mnt_fsname_.c_str(),
103             };
104             android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG,
105                                     true, nullptr, nullptr, 0);
106         }
107     }
108 
IsBlockDevice(const struct mntent & mntent)109     static bool IsBlockDevice(const struct mntent& mntent) {
110         return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
111     }
112 
IsEmulatedDevice(const struct mntent & mntent)113     static bool IsEmulatedDevice(const struct mntent& mntent) {
114         return android::base::StartsWith(mntent.mnt_fsname, "/data/");
115     }
116 
117   private:
IsF2Fs() const118     bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
119 
IsExt4() const120     bool IsExt4() const { return mnt_type_ == "ext4"; }
121 
122     std::string mnt_fsname_;
123     std::string mnt_dir_;
124     std::string mnt_type_;
125     std::string mnt_opts_;
126 };
127 
128 // Turn off backlight while we are performing power down cleanup activities.
TurnOffBacklight()129 static void TurnOffBacklight() {
130     static constexpr char OFF[] = "0";
131 
132     android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
133 
134     static const char backlightDir[] = "/sys/class/backlight";
135     std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
136     if (!dir) {
137         return;
138     }
139 
140     struct dirent* dp;
141     while ((dp = readdir(dir.get())) != nullptr) {
142         if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
143             continue;
144         }
145 
146         std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
147         android::base::WriteStringToFile(OFF, fileName);
148     }
149 }
150 
ShutdownVold()151 static void ShutdownVold() {
152     const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
153     int status;
154     android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true, LOG_KLOG, true,
155                             nullptr, nullptr, 0);
156 }
157 
LogShutdownTime(UmountStat stat,Timer * t)158 static void LogShutdownTime(UmountStat stat, Timer* t) {
159     LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
160 }
161 
162 static void __attribute__((noreturn))
RebootSystem(unsigned int cmd,const std::string & rebootTarget)163 RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
164     LOG(INFO) << "Reboot ending, jumping to kernel";
165     switch (cmd) {
166         case ANDROID_RB_POWEROFF:
167             reboot(RB_POWER_OFF);
168             break;
169 
170         case ANDROID_RB_RESTART2:
171             syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
172                     LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
173             break;
174 
175         case ANDROID_RB_THERMOFF:
176             reboot(RB_POWER_OFF);
177             break;
178     }
179     // In normal case, reboot should not return.
180     PLOG(FATAL) << "reboot call returned";
181     abort();
182 }
183 
184 /* Find all read+write block devices and emulated devices in /proc/mounts
185  * and add them to correpsponding list.
186  */
FindPartitionsToUmount(std::vector<MountEntry> * blockDevPartitions,std::vector<MountEntry> * emulatedPartitions,bool dump)187 static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
188                                    std::vector<MountEntry>* emulatedPartitions, bool dump) {
189     std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
190     if (fp == nullptr) {
191         PLOG(ERROR) << "Failed to open /proc/mounts";
192         return false;
193     }
194     mntent* mentry;
195     while ((mentry = getmntent(fp.get())) != nullptr) {
196         if (dump) {
197             LOG(INFO) << "mount entry " << mentry->mnt_fsname << ":" << mentry->mnt_dir << " opts "
198                       << mentry->mnt_opts << " type " << mentry->mnt_type;
199         } else if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
200             blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
201         } else if (MountEntry::IsEmulatedDevice(*mentry)) {
202             emulatedPartitions->emplace(emulatedPartitions->begin(), *mentry);
203         }
204     }
205     return true;
206 }
207 
DumpUmountDebuggingInfo(bool dump_all)208 static void DumpUmountDebuggingInfo(bool dump_all) {
209     int status;
210     if (!security_getenforce()) {
211         LOG(INFO) << "Run lsof";
212         const char* lsof_argv[] = {"/system/bin/lsof"};
213         android_fork_execvp_ext(arraysize(lsof_argv), (char**)lsof_argv, &status, true, LOG_KLOG,
214                                 true, nullptr, nullptr, 0);
215     }
216     FindPartitionsToUmount(nullptr, nullptr, true);
217     if (dump_all) {
218         // dump current tasks, this log can be lengthy, so only dump with dump_all
219         android::base::WriteStringToFile("t", "/proc/sysrq-trigger");
220     }
221 }
222 
UmountPartitions(int timeoutMs)223 static UmountStat UmountPartitions(int timeoutMs) {
224     Timer t;
225     UmountStat stat = UMOUNT_STAT_TIMEOUT;
226     int retry = 0;
227     /* data partition needs all pending writes to be completed and all emulated partitions
228      * umounted.If the current waiting is not good enough, give
229      * up and leave it to e2fsck after reboot to fix it.
230      */
231     while (true) {
232         std::vector<MountEntry> block_devices;
233         std::vector<MountEntry> emulated_devices;
234         if (!FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
235             return UMOUNT_STAT_ERROR;
236         }
237         if (block_devices.size() == 0) {
238             stat = UMOUNT_STAT_SUCCESS;
239             break;
240         }
241         if ((timeoutMs < t.duration_ms()) && retry > 0) {  // try umount at least once
242             stat = UMOUNT_STAT_TIMEOUT;
243             break;
244         }
245         if (emulated_devices.size() > 0 &&
246             std::all_of(emulated_devices.begin(), emulated_devices.end(),
247                         [](auto& entry) { return entry.Umount(); })) {
248             sync();
249         }
250         for (auto& entry : block_devices) {
251             entry.Umount();
252         }
253         retry++;
254         std::this_thread::sleep_for(100ms);
255     }
256     return stat;
257 }
258 
KillAllProcesses()259 static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
260 
261 /* Try umounting all emulated file systems R/W block device cfile systems.
262  * This will just try umount and give it up if it fails.
263  * For fs like ext4, this is ok as file system will be marked as unclean shutdown
264  * and necessary check can be done at the next reboot.
265  * For safer shutdown, caller needs to make sure that
266  * all processes / emulated partition for the target fs are all cleaned-up.
267  *
268  * return true when umount was successful. false when timed out.
269  */
TryUmountAndFsck(bool runFsck,int timeoutMs)270 static UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
271     Timer t;
272     std::vector<MountEntry> block_devices;
273     std::vector<MountEntry> emulated_devices;
274 
275     TurnOffBacklight();  // this part can take time. save power.
276 
277     if (runFsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
278         return UMOUNT_STAT_ERROR;
279     }
280 
281     UmountStat stat = UmountPartitions(timeoutMs - t.duration_ms());
282     if (stat != UMOUNT_STAT_SUCCESS) {
283         LOG(INFO) << "umount timeout, last resort, kill all and try";
284         if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
285         KillAllProcesses();
286         // even if it succeeds, still it is timeout and do not run fsck with all processes killed
287         UmountPartitions(0);
288         if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
289     }
290 
291     if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
292         // fsck part is excluded from timeout check. It only runs for user initiated shutdown
293         // and should not affect reboot time.
294         for (auto& entry : block_devices) {
295             entry.DoFsck();
296         }
297     }
298     return stat;
299 }
300 
DoThermalOff()301 static void __attribute__((noreturn)) DoThermalOff() {
302     LOG(WARNING) << "Thermal system shutdown";
303     sync();
304     RebootSystem(ANDROID_RB_THERMOFF, "");
305     abort();
306 }
307 
DoReboot(unsigned int cmd,const std::string & reason,const std::string & rebootTarget,bool runFsck)308 void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
309               bool runFsck) {
310     Timer t;
311     LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
312 
313     android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
314                                      S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
315 
316     if (cmd == ANDROID_RB_THERMOFF) {  // do not wait if it is thermal
317         DoThermalOff();
318         abort();
319     }
320 
321     constexpr unsigned int shutdownTimeoutDefault = 6;
322     unsigned int shutdownTimeout = shutdownTimeoutDefault;
323     if (SHUTDOWN_ZERO_TIMEOUT) {  // eng build
324         shutdownTimeout = 0;
325     } else {
326         shutdownTimeout =
327             android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
328     }
329     LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
330 
331     // keep debugging tools until non critical ones are all gone.
332     const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
333     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
334     const std::set<std::string> to_starts{"watchdogd", "vold", "ueventd"};
335     ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
336         if (kill_after_apps.count(s->name())) {
337             s->SetShutdownCritical();
338         } else if (to_starts.count(s->name())) {
339             s->Start();
340             s->SetShutdownCritical();
341         }
342     });
343 
344     Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
345     Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
346     if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
347         ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
348             s->SetShutdownCritical();  // will not check animation class separately
349         });
350     }
351 
352     // optional shutdown step
353     // 1. terminate all services except shutdown critical ones. wait for delay to finish
354     if (shutdownTimeout > 0) {
355         LOG(INFO) << "terminating init services";
356 
357         // Ask all services to terminate except shutdown critical ones.
358         ServiceManager::GetInstance().ForEachService([](Service* s) {
359             if (!s->IsShutdownCritical()) s->Terminate();
360         });
361 
362         int service_count = 0;
363         // Up to half as long as shutdownTimeout or 3 seconds, whichever is lower.
364         unsigned int terminationWaitTimeout = std::min<unsigned int>((shutdownTimeout + 1) / 2, 3);
365         while (t.duration_s() < terminationWaitTimeout) {
366             ServiceManager::GetInstance().ReapAnyOutstandingChildren();
367 
368             service_count = 0;
369             ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
370                 // Count the number of services running except shutdown critical.
371                 // Exclude the console as it will ignore the SIGTERM signal
372                 // and not exit.
373                 // Note: SVC_CONSOLE actually means "requires console" but
374                 // it is only used by the shell.
375                 if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
376                     service_count++;
377                 }
378             });
379 
380             if (service_count == 0) {
381                 // All terminable services terminated. We can exit early.
382                 break;
383             }
384 
385             // Wait a bit before recounting the number or running services.
386             std::this_thread::sleep_for(50ms);
387         }
388         LOG(INFO) << "Terminating running services took " << t
389                   << " with remaining services:" << service_count;
390     }
391 
392     // minimum safety steps before restarting
393     // 2. kill all services except ones that are necessary for the shutdown sequence.
394     ServiceManager::GetInstance().ForEachService([](Service* s) {
395         if (!s->IsShutdownCritical()) s->Stop();
396     });
397     ServiceManager::GetInstance().ReapAnyOutstandingChildren();
398 
399     // 3. send volume shutdown to vold
400     Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
401     if (voldService != nullptr && voldService->IsRunning()) {
402         ShutdownVold();
403         voldService->Stop();
404     } else {
405         LOG(INFO) << "vold not running, skipping vold shutdown";
406     }
407     // logcat stopped here
408     ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
409         if (kill_after_apps.count(s->name())) s->Stop();
410     });
411     // 4. sync, try umount, and optionally run fsck for user shutdown
412     sync();
413     UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
414     // Follow what linux shutdown is doing: one more sync with little bit delay
415     sync();
416     std::this_thread::sleep_for(100ms);
417     LogShutdownTime(stat, &t);
418     // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
419     RebootSystem(cmd, rebootTarget);
420     abort();
421 }
422 
HandlePowerctlMessage(const std::string & command)423 bool HandlePowerctlMessage(const std::string& command) {
424     unsigned int cmd = 0;
425     std::vector<std::string> cmd_params = android::base::Split(command, ",");
426     std::string reboot_target = "";
427     bool run_fsck = false;
428     bool command_invalid = false;
429 
430     if (cmd_params.size() > 3) {
431         command_invalid = true;
432     } else if (cmd_params[0] == "shutdown") {
433         cmd = ANDROID_RB_POWEROFF;
434         if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
435             // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
436             // Run fsck once the file system is remounted in read-only mode.
437             run_fsck = true;
438         }
439     } else if (cmd_params[0] == "reboot") {
440         cmd = ANDROID_RB_RESTART2;
441         if (cmd_params.size() >= 2) {
442             reboot_target = cmd_params[1];
443             // When rebooting to the bootloader notify the bootloader writing
444             // also the BCB.
445             if (reboot_target == "bootloader") {
446                 std::string err;
447                 if (!write_reboot_bootloader(&err)) {
448                     LOG(ERROR) << "reboot-bootloader: Error writing "
449                                   "bootloader_message: "
450                                << err;
451                 }
452             }
453             // If there is an additional bootloader parameter, pass it along
454             if (cmd_params.size() == 3) {
455                 reboot_target += "," + cmd_params[2];
456             }
457         }
458     } else if (command == "thermal-shutdown") {  // no additional parameter allowed
459         cmd = ANDROID_RB_THERMOFF;
460     } else {
461         command_invalid = true;
462     }
463     if (command_invalid) {
464         LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
465         return false;
466     }
467 
468     DoReboot(cmd, command, reboot_target, run_fsck);
469     return true;
470 }
471