init: reboot immediately if /data isn't mounted
All of the logic in reboot.cpp is meant to safely shutdown services,
safely unmount emulated RW file systems, then finally unmount the
remaining RW file systems, particularly /data. If /data hasn't been
mounted, then none of this logic is required.
Running this logic caused a lock up when shutting down blueline from
early-init. Vold, or potentially a related HAL, locked up during the
ShutdownVold() calls. debuggerd separately locked up in the watchdog
thread.
Therefore, this change immediately reboots if /data is not mounted.
It also removes the lines to call into debuggerd. debuggerd will not
run due to SELinux in any case, so it can only be used when hands-on
debugging a device.
Bug: 141082587
Test: shutdown with /data mounted continues as normal
Test: shutdown from early-init immediately shuts the device down
Change-Id: I79c72346b17c7dfe57e955d9739bcaf559badc14
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 786a084..2cf0f5c 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -60,6 +60,8 @@
#define PROC_SYSRQ "/proc/sysrq-trigger"
+using namespace std::literals;
+
using android::base::GetBoolProperty;
using android::base::Split;
using android::base::Timer;
@@ -170,9 +172,23 @@
<< stat;
}
-/* Find all read+write block devices and emulated devices in /proc/mounts
- * and add them to correpsponding list.
- */
+static bool IsDataMounted() {
+ 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 (mentry->mnt_dir == "/data"s) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Find all read+write block devices and emulated devices in /proc/mounts and add them to
+// the correpsponding list.
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);
@@ -295,12 +311,15 @@
LOG(ERROR) << "Reboot thread timed out";
if (android::base::GetBoolProperty("ro.debuggable", false) == true) {
- LOG(INFO) << "Try to dump init process call trace:";
- const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
- int status;
- android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true,
- LOG_KLOG, true, nullptr, nullptr, 0);
-
+ if (false) {
+ // SEPolicy will block debuggerd from running and this is intentional.
+ // But these lines are left to be enabled during debugging.
+ LOG(INFO) << "Try to dump init process call trace:";
+ const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
+ int status;
+ android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true,
+ LOG_KLOG, true, nullptr, nullptr, 0);
+ }
LOG(INFO) << "Show stack for all active CPU:";
WriteStringToFile("l", PROC_SYSRQ);
@@ -436,6 +455,14 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
+ // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
+ // worry about unmounting it.
+ if (!IsDataMounted()) {
+ sync();
+ RebootSystem(cmd, rebootTarget);
+ abort();
+ }
+
// Ensure last reboot reason is reduced to canonical
// alias reported in bootloader or system boot reason.
size_t skip = 0;