From 92116e4129812eccb32d7a20208e03be7ee2ec75 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Tue, 31 Mar 2020 01:28:35 +0100 Subject: [PATCH] Properly fail userspace reboot if it's not supported Previously, after `adb reboot userspace` is called on a device that doesn't suppor it, init would've logged an error and quietly exit the shutdown sequence. This was leaving adb handing forever. With this approach, init will fail setprop "sys.powerctl=reboot,userspace" in case userspace reboot is not supported. Test: adb root Test: adb setprop init.userspace_reboot.is_supported 0 Test: adb reboot userspace Test: atest CtsInitTestCases Bug: 146639622 Change-Id: I1264078f53ed3ff54638c7f3b6846b7437f98ee5 --- init/property_service.cpp | 6 ++++++ init/property_service_test.cpp | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/init/property_service.cpp b/init/property_service.cpp index 655b8deef..842b2e5b7 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -85,6 +86,7 @@ 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 { @@ -492,6 +494,10 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value, if (!value.empty()) { DebugRebootLogging(); } + if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) { + *error = "Userspace reboot is not supported by this device"; + return PROP_ERROR_INVALID_VALUE; + } } // If a process other than init is writing a non-empty value, it means that process is diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp index 0f4cd0d1f..c6dcfa257 100644 --- a/init/property_service_test.cpp +++ b/init/property_service_test.cpp @@ -22,8 +22,10 @@ #include #include +#include #include +using android::base::GetProperty; using android::base::SetProperty; namespace android { @@ -74,5 +76,19 @@ TEST(property_service, non_utf8_value) { EXPECT_TRUE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\x80")); } +TEST(property_service, userspace_reboot_not_supported) { + if (getuid() != 0) { + 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")); +} + } // namespace init } // namespace android