diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index 4eb738205..4043a6e03 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp @@ -159,7 +159,8 @@ noinline void sigsegv_non_null() { } noinline void fprintf_null() { - fprintf(nullptr, "oops"); + FILE* sneaky_null = nullptr; + fprintf(sneaky_null, "oops"); } noinline void readdir_null() { diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 15f025c9c..f655522c6 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -3216,6 +3216,8 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife vabc_disable_reason = "recovery"; } else if (!cow_format_support) { vabc_disable_reason = "cow format not supported"; + } else if (!KernelSupportsCompressedSnapshots()) { + vabc_disable_reason = "kernel missing userspace block device support"; } if (!vabc_disable_reason.empty()) { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 13314daab..460d49db2 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -124,6 +124,10 @@ class SnapshotTest : public ::testing::Test { SKIP_IF_NON_VIRTUAL_AB(); SetupProperties(); + if (!DeviceSupportsMode()) { + GTEST_SKIP() << "Mode not supported on this device"; + } + InitializeState(); CleanupTestArtifacts(); FormatFakeSuper(); @@ -159,7 +163,13 @@ class SnapshotTest : public ::testing::Test { IPropertyFetcher::OverrideForTesting(std::move(fetcher)); if (GetLegacyCompressionEnabledProperty() || CanUseUserspaceSnapshots()) { - snapuserd_required_ = true; + // If we're asked to test the device's actual configuration, then it + // may be misconfigured, so check for kernel support as libsnapshot does. + if (FLAGS_force_mode.empty()) { + snapuserd_required_ = KernelSupportsCompressedSnapshots(); + } else { + snapuserd_required_ = true; + } } } @@ -176,6 +186,16 @@ class SnapshotTest : public ::testing::Test { LOG(INFO) << "Teardown complete for test: " << test_name_; } + bool DeviceSupportsMode() { + if (FLAGS_force_mode.empty()) { + return true; + } + if (snapuserd_required_ && !KernelSupportsCompressedSnapshots()) { + return false; + } + return true; + } + void InitializeState() { ASSERT_TRUE(sm->EnsureImageManager()); image_manager_ = sm->image_manager(); @@ -193,6 +213,11 @@ class SnapshotTest : public ::testing::Test { // get an accurate list to remove. lock_ = nullptr; + // If there is no image manager, the test was skipped. + if (!image_manager_) { + return; + } + std::vector snapshots = {"test-snapshot", "test_partition_a", "test_partition_b"}; for (const auto& snapshot : snapshots) { @@ -946,6 +971,11 @@ class SnapshotUpdateTest : public SnapshotTest { SKIP_IF_NON_VIRTUAL_AB(); SnapshotTest::SetUp(); + if (!image_manager_) { + // Test was skipped. + return; + } + Cleanup(); // Cleanup() changes slot suffix, so initialize it again. @@ -2680,6 +2710,9 @@ class ImageManagerTest : public SnapshotTest { CleanUp(); } void CleanUp() { + if (!image_manager_) { + return; + } EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) || image_manager_->DeleteBackingImage(kImageName)); } diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp index a98bf0e5c..1ffa89cba 100644 --- a/fs_mgr/libsnapshot/utility.cpp +++ b/fs_mgr/libsnapshot/utility.cpp @@ -29,6 +29,7 @@ #include #include +using android::dm::DeviceMapper; using android::dm::kSectorSize; using android::fiemap::FiemapStatus; using android::fs_mgr::EnsurePathMounted; @@ -251,7 +252,10 @@ bool CanUseUserspaceSnapshots() { LOG(INFO) << "Userspace snapshots disabled for testing"; return false; } - + if (!KernelSupportsCompressedSnapshots()) { + LOG(ERROR) << "Userspace snapshots requested, but no kernel support is available."; + return false; + } return true; } @@ -278,5 +282,10 @@ bool IsDmSnapshotTestingEnabled() { return fetcher->GetBoolProperty("snapuserd.test.dm.snapshots", false); } +bool KernelSupportsCompressedSnapshots() { + auto& dm = DeviceMapper::Instance(); + return dm.GetTargetByName("user", nullptr); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h index 8c4c7c664..370f3c4fc 100644 --- a/fs_mgr/libsnapshot/utility.h +++ b/fs_mgr/libsnapshot/utility.h @@ -127,6 +127,8 @@ std::ostream& operator<<(std::ostream& os, const Now&); void AppendExtent(google::protobuf::RepeatedPtrField* extents, uint64_t start_block, uint64_t num_blocks); +bool KernelSupportsCompressedSnapshots(); + bool GetLegacyCompressionEnabledProperty(); bool GetUserspaceSnapshotsEnabledProperty(); bool GetIouringEnabledProperty(); diff --git a/init/init.cpp b/init/init.cpp index e18afed87..e8150f8cb 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -261,48 +261,21 @@ static class ShutdownState { WakeMainInitThread(); } - std::optional CheckShutdown() { + std::optional CheckShutdown() __attribute__((warn_unused_result)) { auto lock = std::lock_guard{shutdown_command_lock_}; if (do_shutdown_ && !IsShuttingDown()) { + do_shutdown_ = false; return shutdown_command_; } return {}; } - bool do_shutdown() const { return do_shutdown_; } - void set_do_shutdown(bool value) { do_shutdown_ = value; } - private: std::mutex shutdown_command_lock_; std::string shutdown_command_ GUARDED_BY(shutdown_command_lock_); bool do_shutdown_ = false; } shutdown_state; -static void UnwindMainThreadStack() { - unwindstack::AndroidLocalUnwinder unwinder; - unwindstack::AndroidUnwinderData data; - if (!unwinder.Unwind(data)) { - LOG(ERROR) << __FUNCTION__ - << "sys.powerctl: Failed to unwind callstack: " << data.GetErrorString(); - } - for (const auto& frame : data.frames) { - LOG(ERROR) << "sys.powerctl: " << unwinder.FormatFrame(frame); - } -} - -void DebugRebootLogging() { - LOG(INFO) << "sys.powerctl: do_shutdown: " << shutdown_state.do_shutdown() - << " IsShuttingDown: " << IsShuttingDown(); - if (shutdown_state.do_shutdown()) { - LOG(ERROR) << "sys.powerctl set while a previous shutdown command has not been handled"; - UnwindMainThreadStack(); - } - if (IsShuttingDown()) { - LOG(ERROR) << "sys.powerctl set while init is already shutting down"; - UnwindMainThreadStack(); - } -} - void DumpState() { ServiceList::GetInstance().DumpState(); ActionManager::GetInstance().DumpState(); @@ -1138,36 +1111,43 @@ int SecondStageMain(int argc, char** argv) { // Restore prio before main loop setpriority(PRIO_PROCESS, 0, 0); while (true) { - // By default, sleep until something happens. - std::optional epoll_timeout; + // By default, sleep until something happens. Do not convert far_future into + // std::chrono::milliseconds because that would trigger an overflow. The unit of boot_clock + // is 1ns. + const boot_clock::time_point far_future = boot_clock::time_point::max(); + boot_clock::time_point next_action_time = far_future; auto shutdown_command = shutdown_state.CheckShutdown(); if (shutdown_command) { LOG(INFO) << "Got shutdown_command '" << *shutdown_command << "' Calling HandlePowerctlMessage()"; HandlePowerctlMessage(*shutdown_command); - shutdown_state.set_do_shutdown(false); } if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) { am.ExecuteOneCommand(); + // If there's more work to do, wake up again immediately. + if (am.HasMoreCommands()) { + next_action_time = boot_clock::now(); + } } + // Since the above code examined pending actions, no new actions must be + // queued by the code between this line and the Epoll::Wait() call below + // without calling WakeMainInitThread(). if (!IsShuttingDown()) { auto next_process_action_time = HandleProcessActions(); // If there's a process that needs restarting, wake up in time for that. if (next_process_action_time) { - epoll_timeout = std::chrono::ceil( - *next_process_action_time - boot_clock::now()); - if (epoll_timeout < 0ms) epoll_timeout = 0ms; + next_action_time = std::min(next_action_time, *next_process_action_time); } } - if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) { - // If there's more work to do, wake up again immediately. - if (am.HasMoreCommands()) epoll_timeout = 0ms; + std::optional epoll_timeout; + if (next_action_time != far_future) { + epoll_timeout = std::chrono::ceil( + std::max(next_action_time - boot_clock::now(), 0ns)); } - auto epoll_result = epoll.Wait(epoll_timeout); if (!epoll_result.ok()) { LOG(ERROR) << epoll_result.error(); diff --git a/init/init.h b/init/init.h index 063632a66..9c7e91879 100644 --- a/init/init.h +++ b/init/init.h @@ -42,8 +42,6 @@ void SendLoadPersistentPropertiesMessage(); void PropertyChanged(const std::string& name, const std::string& value); bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd); -void DebugRebootLogging(); - int SecondStageMain(int argc, char** argv); int StopServicesFromApex(const std::string& apex_name); diff --git a/init/property_service.cpp b/init/property_service.cpp index 189622843..33c9bebac 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -552,9 +552,6 @@ std::optional HandlePropertySet(const std::string& name, const std::st } LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid << process_log_string; - 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};