Clean up userspace-reboot

The feature was deprecated last year.

Bug: 292469129
Test: atest CtsInitTestCases
Change-Id: I826502770ab3fa566be57a33829f1103efa893fb
This commit is contained in:
Jooyung Han 2024-08-09 15:58:53 +09:00
parent 6d85bb3ef5
commit e34549af33
9 changed files with 15 additions and 526 deletions

View file

@ -1433,16 +1433,16 @@ bool WasMetadataEncryptionInterrupted(const FstabEntry& entry) {
// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
int error_count = 0;
CheckpointManager checkpoint_manager;
AvbUniquePtr avb_handle(nullptr);
bool wiped = false;
bool userdata_mounted = false;
if (fstab->empty()) {
return {FS_MGR_MNTALL_FAIL, userdata_mounted};
return FS_MGR_MNTALL_FAIL;
}
bool scratch_can_be_mounted = true;
@ -1521,7 +1521,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
if (!avb_handle) {
LERROR << "Failed to open AvbHandle";
set_type_property(encryptable);
return {FS_MGR_MNTALL_FAIL, userdata_mounted};
return FS_MGR_MNTALL_FAIL;
}
}
if (avb_handle->SetUpAvbHashtree(&current_entry, true /* wait_for_verity_dev */) ==
@ -1557,7 +1557,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
if (status == FS_MGR_MNTALL_FAIL) {
// Fatal error - no point continuing.
return {status, userdata_mounted};
return status;
}
if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
@ -1577,7 +1577,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
nullptr)) {
LERROR << "Encryption failed";
set_type_property(encryptable);
return {FS_MGR_MNTALL_FAIL, userdata_mounted};
return FS_MGR_MNTALL_FAIL;
}
}
}
@ -1696,9 +1696,9 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
set_type_property(encryptable);
if (error_count) {
return {FS_MGR_MNTALL_FAIL, userdata_mounted};
return FS_MGR_MNTALL_FAIL;
} else {
return {encryptable, userdata_mounted};
return encryptable;
}
}
@ -1735,190 +1735,6 @@ int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
return ret;
}
static std::chrono::milliseconds GetMillisProperty(const std::string& name,
std::chrono::milliseconds default_value) {
auto value = GetUintProperty(name, static_cast<uint64_t>(default_value.count()));
return std::chrono::milliseconds(std::move(value));
}
static bool fs_mgr_unmount_all_data_mounts(const std::string& data_block_device) {
LINFO << __FUNCTION__ << "(): about to umount everything on top of " << data_block_device;
Timer t;
auto timeout = GetMillisProperty("init.userspace_reboot.userdata_remount.timeoutmillis", 5s);
while (true) {
bool umount_done = true;
Fstab proc_mounts;
if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
return false;
}
// Now proceed with other bind mounts on top of /data.
for (const auto& entry : proc_mounts) {
std::string block_device;
if (StartsWith(entry.blk_device, "/dev/block") &&
!Realpath(entry.blk_device, &block_device)) {
PWARNING << __FUNCTION__ << "(): failed to realpath " << entry.blk_device;
block_device = entry.blk_device;
}
if (data_block_device == block_device) {
if (umount2(entry.mount_point.c_str(), 0) != 0) {
PERROR << __FUNCTION__ << "(): Failed to umount " << entry.mount_point;
umount_done = false;
}
}
}
if (umount_done) {
LINFO << __FUNCTION__ << "(): Unmounting /data took " << t;
return true;
}
if (t.duration() > timeout) {
LERROR << __FUNCTION__ << "(): Timed out unmounting all mounts on "
<< data_block_device;
Fstab remaining_mounts;
if (!ReadFstabFromFile("/proc/mounts", &remaining_mounts)) {
LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
} else {
LERROR << __FUNCTION__ << "(): Following mounts remaining";
for (const auto& e : remaining_mounts) {
LERROR << __FUNCTION__ << "(): mount point: " << e.mount_point
<< " block device: " << e.blk_device;
}
}
return false;
}
std::this_thread::sleep_for(50ms);
}
}
static bool UnwindDmDeviceStack(const std::string& block_device,
std::vector<std::string>* dm_stack) {
if (!StartsWith(block_device, "/dev/block/")) {
LWARNING << block_device << " is not a block device";
return false;
}
std::string current = block_device;
DeviceMapper& dm = DeviceMapper::Instance();
while (true) {
dm_stack->push_back(current);
if (!dm.IsDmBlockDevice(current)) {
break;
}
auto parent = dm.GetParentBlockDeviceByPath(current);
if (!parent) {
return false;
}
current = *parent;
}
return true;
}
FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab,
const std::string& data_block_device) {
std::vector<std::string> dm_stack;
if (!UnwindDmDeviceStack(data_block_device, &dm_stack)) {
LERROR << "Failed to unwind dm-device stack for " << data_block_device;
return nullptr;
}
for (auto& entry : *fstab) {
if (entry.mount_point != "/data") {
continue;
}
std::string block_device;
if (entry.fs_mgr_flags.logical) {
if (!fs_mgr_update_logical_partition(&entry)) {
LERROR << "Failed to update logic partition " << entry.blk_device;
continue;
}
block_device = entry.blk_device;
} else if (!Realpath(entry.blk_device, &block_device)) {
PWARNING << "Failed to realpath " << entry.blk_device;
block_device = entry.blk_device;
}
if (std::find(dm_stack.begin(), dm_stack.end(), block_device) != dm_stack.end()) {
return &entry;
}
}
LERROR << "Didn't find entry that was used to mount /data onto " << data_block_device;
return nullptr;
}
// TODO(b/143970043): return different error codes based on which step failed.
int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
Fstab proc_mounts;
if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
LERROR << "Can't read /proc/mounts";
return -1;
}
auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
if (mounted_entry == nullptr) {
LERROR << "/data is not mounted";
return -1;
}
std::string block_device;
if (!Realpath(mounted_entry->blk_device, &block_device)) {
PERROR << "Failed to realpath " << mounted_entry->blk_device;
return -1;
}
auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, block_device);
if (fstab_entry == nullptr) {
LERROR << "Can't find /data in fstab";
return -1;
}
bool force_umount = GetBoolProperty("sys.init.userdata_remount.force_umount", false);
if (force_umount) {
LINFO << "Will force an umount of userdata even if it's not required";
}
if (!force_umount && !SupportsCheckpoint(fstab_entry)) {
LINFO << "Userdata doesn't support checkpointing. Nothing to do";
return 0;
}
CheckpointManager checkpoint_manager;
if (!force_umount && !checkpoint_manager.NeedsCheckpoint()) {
LINFO << "Checkpointing not needed. Don't remount";
return 0;
}
if (!force_umount && fstab_entry->fs_mgr_flags.checkpoint_fs) {
// Userdata is f2fs, simply remount it.
if (!checkpoint_manager.Update(fstab_entry)) {
LERROR << "Failed to remount userdata in checkpointing mode";
return -1;
}
if (mount(block_device.c_str(), fstab_entry->mount_point.c_str(), "none",
MS_REMOUNT | fstab_entry->flags, fstab_entry->fs_options.c_str()) != 0) {
PERROR << "Failed to remount userdata in checkpointing mode";
return -1;
}
} else {
LINFO << "Unmounting /data before remounting into checkpointing mode";
if (!fs_mgr_unmount_all_data_mounts(block_device)) {
LERROR << "Failed to umount /data";
return -1;
}
DeviceMapper& dm = DeviceMapper::Instance();
while (dm.IsDmBlockDevice(block_device)) {
auto next_device = dm.GetParentBlockDeviceByPath(block_device);
auto name = dm.GetDmDeviceNameByPath(block_device);
if (!name) {
LERROR << "Failed to get dm-name for " << block_device;
return -1;
}
LINFO << "Deleting " << block_device << " named " << *name;
if (!dm.DeleteDevice(*name, 3s)) {
return -1;
}
if (!next_device) {
LERROR << "Failed to find parent device for " << block_device;
}
block_device = *next_device;
}
LINFO << "Remounting /data";
// TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
auto result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
return result.code == FS_MGR_MNTALL_FAIL ? -1 : 0;
}
return 0;
}
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_point) {

View file

@ -58,13 +58,8 @@ enum mount_mode {
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
struct MountAllResult {
// One of the FS_MGR_MNTALL_* returned code defined above.
int code;
// Whether userdata was mounted as a result of |fs_mgr_mount_all| call.
bool userdata_mounted;
};
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
int fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
struct HashtreeInfo {
// The hash algorithm used to build the merkle tree.
@ -75,13 +70,6 @@ struct HashtreeInfo {
bool check_at_most_once;
};
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
// Returns a |MountAllResult|. The first element is one of the FS_MNG_MNTALL_* return codes
// defined above, and the second element tells whether this call to fs_mgr_mount_all was responsible
// for mounting userdata. Later is required for init to correctly enqueue fs-related events as part
// of userdata remount during userspace reboot.
MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
@ -127,11 +115,6 @@ enum FsMgrUmountStatus : int {
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
// Finds a entry in |fstab| that was used to mount a /data on |data_block_device|.
android::fs_mgr::FstabEntry* fs_mgr_get_mounted_entry_for_userdata(
android::fs_mgr::Fstab* fstab, const std::string& data_block_device);
int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
// Finds the dm_bow device on which this block device is stacked, or returns
// empty string
std::string fs_mgr_find_bow_device(const std::string& block_device);

View file

@ -1062,23 +1062,6 @@ TEST(fs_mgr, DefaultFstabContainsUserdata) {
<< "Default fstab doesn't contain /data entry";
}
TEST(fs_mgr, UserdataMountedFromDefaultFstab) {
if (getuid() != 0) {
GTEST_SKIP() << "Must be run as root.";
return;
}
Fstab fstab;
ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
Fstab proc_mounts;
ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts";
auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted";
std::string block_device;
ASSERT_TRUE(android::base::Realpath(mounted_entry->blk_device, &block_device));
ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
<< "/data wasn't mounted from default fstab";
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);

View file

@ -606,8 +606,6 @@ static Result<void> queue_fs_event(int code) {
return Error() << "Invalid code: " << code;
}
static int initial_mount_fstab_return_code = -1;
/* <= Q: mount_all <fstab> [ <path> ]* [--<options>]*
* >= R: mount_all [ <fstab> ] [--<options>]*
*
@ -648,19 +646,10 @@ static Result<void> do_mount_all(const BuiltinArguments& args) {
import_late(mount_all->rc_paths);
}
if (mount_fstab_result.userdata_mounted) {
// This call to fs_mgr_mount_all mounted userdata. Keep the result in
// order for userspace reboot to correctly remount userdata.
LOG(INFO) << "Userdata mounted using "
<< (mount_all->fstab_path.empty() ? "(default fstab)" : mount_all->fstab_path)
<< " result : " << mount_fstab_result.code;
initial_mount_fstab_return_code = mount_fstab_result.code;
}
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
auto queue_fs_result = queue_fs_event(mount_fstab_result.code);
auto queue_fs_result = queue_fs_event(mount_fstab_result);
if (!queue_fs_result.ok()) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
}
@ -1178,29 +1167,6 @@ static Result<void> ExecVdcRebootOnFailure(const std::string& vdc_arg) {
return ExecWithFunctionOnFailure(args, reboot);
}
static Result<void> do_remount_userdata(const BuiltinArguments& args) {
if (initial_mount_fstab_return_code == -1) {
return Error() << "Calling remount_userdata too early";
}
Fstab fstab;
if (!ReadDefaultFstab(&fstab)) {
// TODO(b/135984674): should we reboot here?
return Error() << "Failed to read fstab";
}
// TODO(b/135984674): check that fstab contains /data.
if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
std::string proc_mounts_output;
android::base::ReadFileToString("/proc/mounts", &proc_mounts_output, true);
android::base::WriteStringToFile(proc_mounts_output,
"/metadata/userspacereboot/mount_info.txt");
trigger_shutdown("reboot,mount_userdata_failed");
}
if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result.ok()) {
return Error() << "queue_fs_event() failed: " << result.error();
}
return {};
}
static Result<void> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return {};
@ -1361,7 +1327,6 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
{"umount_all", {0, 1, {false, do_umount_all}}},
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"remount_userdata", {0, 0, {false, do_remount_userdata}}},
{"restart", {1, 2, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},

View file

@ -102,7 +102,6 @@ using android::properties::BuildTrie;
using android::properties::ParsePropertyInfoFile;
using android::properties::PropertyInfoAreaFile;
using android::properties::PropertyInfoEntry;
using android::sysprop::InitProperties::is_userspace_reboot_supported;
namespace android {
namespace init {
@ -569,8 +568,8 @@ std::optional<uint32_t> HandlePropertySet(const std::string& name, const std::st
}
LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
<< process_log_string;
if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
*error = "Userspace reboot is not supported by this device";
if (value == "reboot,userspace") {
*error = "Userspace reboot is deprecated.";
return {PROP_ERROR_INVALID_VALUE};
}
}

View file

@ -82,12 +82,6 @@ TEST(property_service, userspace_reboot_not_supported) {
GTEST_SKIP() << "Skipping test, must be run as root.";
return;
}
const std::string original_value = GetProperty("init.userspace_reboot.is_supported", "");
auto guard = android::base::make_scope_guard([&original_value]() {
SetProperty("init.userspace_reboot.is_supported", original_value);
});
ASSERT_TRUE(SetProperty("init.userspace_reboot.is_supported", "false"));
EXPECT_FALSE(SetProperty("sys.powerctl", "reboot,userspace"));
}

View file

@ -87,16 +87,6 @@ static bool shutting_down = false;
static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
static std::set<std::string> GetPostDataDebuggingServices() {
std::set<std::string> ret;
for (const auto& s : ServiceList::GetInstance()) {
if (kDebuggingServices.count(s->name()) && s->is_post_data()) {
ret.insert(s->name());
}
}
return ret;
}
static void PersistRebootReason(const char* reason, bool write_to_property) {
if (write_to_property) {
SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
@ -810,196 +800,6 @@ static void EnterShutdown() {
}
}
static void LeaveShutdown() {
LOG(INFO) << "Leaving shutdown mode";
shutting_down = false;
StartSendingMessages();
}
static std::chrono::milliseconds GetMillisProperty(const std::string& name,
std::chrono::milliseconds default_value) {
auto value = GetUintProperty(name, static_cast<uint64_t>(default_value.count()));
return std::chrono::milliseconds(std::move(value));
}
static Result<void> DoUserspaceReboot() {
LOG(INFO) << "Userspace reboot initiated";
// An ugly way to pass a more precise reason on why fallback to hard reboot was triggered.
std::string sub_reason = "";
auto guard = android::base::make_scope_guard([&sub_reason] {
// Leave shutdown so that we can handle a full reboot.
LeaveShutdown();
trigger_shutdown("reboot,userspace_failed,shutdown_aborted," + sub_reason);
});
// Triggering userspace-reboot-requested will result in a bunch of setprop
// actions. We should make sure, that all of them are propagated before
// proceeding with userspace reboot. Synchronously setting sys.init.userspace_reboot.in_progress
// property is not perfect, but it should do the trick.
if (!android::sysprop::InitProperties::userspace_reboot_in_progress(true)) {
sub_reason = "setprop";
return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
}
EnterShutdown();
if (!SetProperty("sys.powerctl", "")) {
sub_reason = "resetprop";
return Error() << "Failed to reset sys.powerctl property";
}
std::set<std::string> stop_first;
// Remember the services that were enabled. We will need to manually enable them again otherwise
// triggers like class_start won't restart them.
std::set<std::string> were_enabled;
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
if (s->is_post_data() && !kDebuggingServices.count(s->name())) {
stop_first.insert(s->name());
}
// TODO(ioffe): we should also filter out temporary services here.
if (s->is_post_data() && s->IsEnabled()) {
were_enabled.insert(s->name());
}
}
{
Timer sync_timer;
LOG(INFO) << "sync() before terminating services...";
sync();
LOG(INFO) << "sync() took " << sync_timer;
}
auto sigterm_timeout = GetMillisProperty("init.userspace_reboot.sigterm.timeoutmillis", 5s);
auto sigkill_timeout = GetMillisProperty("init.userspace_reboot.sigkill.timeoutmillis", 10s);
LOG(INFO) << "Timeout to terminate services: " << sigterm_timeout.count() << "ms "
<< "Timeout to kill services: " << sigkill_timeout.count() << "ms";
std::string services_file_name = "/metadata/userspacereboot/services.txt";
const int flags = O_RDWR | O_CREAT | O_SYNC | O_APPEND | O_CLOEXEC;
StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
r > 0) {
auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
android::base::WriteStringToFd("Post-data services still running: \n", fd);
for (const auto& s : ServiceList::GetInstance()) {
if (s->IsRunning() && stop_first.count(s->name())) {
android::base::WriteStringToFd(s->name() + "\n", fd);
}
}
sub_reason = "sigkill";
return Error() << r << " post-data services are still running";
}
if (auto result = KillZramBackingDevice(); !result.ok()) {
sub_reason = "zram";
return result;
}
if (auto result = CallVdc("volume", "reset"); !result.ok()) {
sub_reason = "vold_reset";
return result;
}
const auto& debugging_services = GetPostDataDebuggingServices();
if (int r = StopServicesAndLogViolations(debugging_services, sigkill_timeout,
false /* SIGKILL */);
r > 0) {
auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
android::base::WriteStringToFd("Debugging services still running: \n", fd);
for (const auto& s : ServiceList::GetInstance()) {
if (s->IsRunning() && debugging_services.count(s->name())) {
android::base::WriteStringToFd(s->name() + "\n", fd);
}
}
sub_reason = "sigkill_debug";
return Error() << r << " debugging services are still running";
}
{
Timer sync_timer;
LOG(INFO) << "sync() after stopping services...";
sync();
LOG(INFO) << "sync() took " << sync_timer;
}
if (auto result = UnmountAllApexes(); !result.ok()) {
sub_reason = "apex";
return result;
}
if (!SwitchToMountNamespaceIfNeeded(NS_BOOTSTRAP).ok()) {
sub_reason = "ns_switch";
return Error() << "Failed to switch to bootstrap namespace";
}
ActionManager::GetInstance().RemoveActionIf([](const auto& action) -> bool {
if (action->IsFromApex()) {
std::string trigger_name = action->BuildTriggersString();
LOG(INFO) << "Removing action (" << trigger_name << ") from (" << action->filename()
<< ":" << action->line() << ")";
return true;
}
return false;
});
// Remove services that were defined in an APEX
ServiceList::GetInstance().RemoveServiceIf([](const std::unique_ptr<Service>& s) -> bool {
if (s->is_from_apex()) {
LOG(INFO) << "Removing service '" << s->name() << "' because it's defined in an APEX";
return true;
}
return false;
});
// Re-enable services
for (const auto& s : ServiceList::GetInstance()) {
if (were_enabled.count(s->name())) {
LOG(INFO) << "Re-enabling service '" << s->name() << "'";
s->Enable();
}
}
ServiceList::GetInstance().ResetState();
LeaveShutdown();
ActionManager::GetInstance().QueueEventTrigger("userspace-reboot-resume");
guard.Disable(); // Go on with userspace reboot.
return {};
}
static void UserspaceRebootWatchdogThread() {
auto started_timeout = GetMillisProperty("init.userspace_reboot.started.timeoutmillis", 10s);
if (!WaitForProperty("sys.init.userspace_reboot.in_progress", "1", started_timeout)) {
LOG(ERROR) << "Userspace reboot didn't start in " << started_timeout.count()
<< "ms. Switching to full reboot";
// Init might be wedged, don't try to write reboot reason into a persistent property and do
// a dirty reboot.
PersistRebootReason("userspace_failed,watchdog_triggered,failed_to_start", false);
RebootSystem(ANDROID_RB_RESTART2, "userspace_failed,watchdog_triggered,failed_to_start");
}
LOG(INFO) << "Starting userspace reboot watchdog";
auto watchdog_timeout = GetMillisProperty("init.userspace_reboot.watchdog.timeoutmillis", 5min);
LOG(INFO) << "UserspaceRebootWatchdog timeout: " << watchdog_timeout.count() << "ms";
if (!WaitForProperty("sys.boot_completed", "1", watchdog_timeout)) {
LOG(ERROR) << "Failed to boot in " << watchdog_timeout.count()
<< "ms. Switching to full reboot";
// In this case device is in a boot loop. Only way to recover is to do dirty reboot.
// Since init might be wedged, don't try to write reboot reason into a persistent property.
PersistRebootReason("userspace_failed,watchdog_triggered,failed_to_boot", false);
RebootSystem(ANDROID_RB_RESTART2, "userspace_failed,watchdog_triggered,failed_to_boot");
}
LOG(INFO) << "Device booted, stopping userspace reboot watchdog";
}
static void HandleUserspaceReboot() {
if (!android::sysprop::InitProperties::is_userspace_reboot_supported().value_or(false)) {
LOG(ERROR) << "Attempted a userspace reboot on a device that doesn't support it";
return;
}
// Spinnig up a separate thread will fail the setns call later in the boot sequence.
// Fork a new process to monitor userspace reboot while we are investigating a better solution.
pid_t pid = fork();
if (pid < 0) {
PLOG(ERROR) << "Failed to fork process for userspace reboot watchdog. Switching to full "
<< "reboot";
trigger_shutdown("reboot,userspace_failed,watchdog_fork");
return;
}
if (pid == 0) {
// Child
UserspaceRebootWatchdogThread();
_exit(EXIT_SUCCESS);
}
LOG(INFO) << "Clearing queue and starting userspace-reboot-requested trigger";
auto& am = ActionManager::GetInstance();
am.ClearQueue();
am.QueueEventTrigger("userspace-reboot-requested");
auto handler = [](const BuiltinArguments&) { return DoUserspaceReboot(); };
am.QueueBuiltinAction(handler, "userspace-reboot");
}
/**
* Check if "command" field is set in bootloader message.
*
@ -1030,7 +830,6 @@ void HandlePowerctlMessage(const std::string& command) {
std::string reboot_target = "";
bool run_fsck = false;
bool command_invalid = false;
bool userspace_reboot = false;
if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
@ -1051,8 +850,8 @@ void HandlePowerctlMessage(const std::string& command) {
if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
if (reboot_target == "userspace") {
LOG(INFO) << "Userspace reboot requested";
userspace_reboot = true;
LOG(ERROR) << "Userspace reboot is deprecated.";
return;
}
// adb reboot fastboot should boot into bootloader for devices not
// supporting logical partitions.
@ -1130,11 +929,6 @@ void HandlePowerctlMessage(const std::string& command) {
// messages, etc) from properties during reboot.
StopSendingMessages();
if (userspace_reboot) {
HandleUserspaceReboot();
return;
}
LOG(INFO) << "Clear action queue and start shutdown trigger";
ActionManager::GetInstance().ClearQueue();
// Queue shutdown trigger first

View file

@ -620,7 +620,6 @@ on post-fs
mkdir /metadata/bootstat 0750 system log
mkdir /metadata/ota 0750 root system
mkdir /metadata/ota/snapshots 0750 root system
mkdir /metadata/userspacereboot 0770 root system
mkdir /metadata/watchdog 0770 root system
mkdir /metadata/apex 0700 root system
@ -1323,46 +1322,6 @@ on property:ro.debuggable=1
on init && property:ro.debuggable=1
start console
on userspace-reboot-requested
# TODO(b/135984674): reset all necessary properties here.
setprop sys.boot_completed ""
setprop dev.bootcomplete ""
setprop sys.init.updatable_crashing ""
setprop sys.init.updatable_crashing_process_name ""
setprop sys.user.0.ce_available ""
setprop sys.shutdown.requested ""
setprop service.bootanim.exit ""
setprop service.bootanim.progress ""
on userspace-reboot-fs-remount
# Make sure that vold is running.
# This is mostly a precaution measure in case vold for some reason wasn't running when
# userspace reboot was initiated.
start vold
exec - system system -- /system/bin/vdc checkpoint resetCheckpoint
exec - system system -- /system/bin/vdc checkpoint markBootAttempt
# Unmount /data_mirror mounts in the reverse order of corresponding mounts.
umount /data_mirror/data_ce/null/0
umount /data_mirror/data_ce/null
umount /data_mirror/data_de/null
umount /data_mirror/storage_area/0
umount /data_mirror/storage_area
umount /data_mirror/cur_profiles
umount /data_mirror/ref_profiles
umount /data_mirror
remount_userdata
start bootanim
on userspace-reboot-resume
trigger userspace-reboot-fs-remount
trigger post-fs-data
trigger zygote-start
trigger early-boot
trigger boot
on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
setprop sys.init.userspace_reboot.in_progress ""
# Multi-Gen LRU Experiment
on property:persist.device_config.mglru_native.lru_gen_config=none
write /sys/kernel/mm/lru_gen/enabled 0

View file

@ -139,7 +139,3 @@ on property:sys.usb.typec.power_role=source
on property:sys.usb.typec.power_role=sink
write /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power_role}
setprop sys.usb.typec.state ${sys.usb.typec.power_role}
on userspace-reboot-requested
setprop sys.usb.config ""
setprop sys.usb.state ""