From 1266930e8aecf50b7f73de0bf1525e6a32b257bc Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 21 Jun 2017 13:02:57 -0700 Subject: [PATCH] Revert "Revert "init: poll in first stage mount if required devices are not found"" This reverts commit d6fccea093ebe5a5d929549d721185b0f1b52ac0. Bug: 62681642 Bug: 62682821 Bug: 62864413 Merged-In: Ic9c27552acbd2ae312e44ea2cdf060dcf493bfe6 Change-Id: Ic9c27552acbd2ae312e44ea2cdf060dcf493bfe6 Signed-off-by: Sandeep Patil (cherry picked from commit 4cbedee541d92b408c591e4fc16d88a0653c076c) --- init/init_first_stage.cpp | 120 +++++++++++++++++++++++--------------- init/uevent_listener.cpp | 50 +++++++++++----- init/uevent_listener.h | 18 +++--- init/ueventd.cpp | 5 +- 4 files changed, 120 insertions(+), 73 deletions(-) diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp index 5c31997c0..4faca8965 100644 --- a/init/init_first_stage.cpp +++ b/init/init_first_stage.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include "uevent_listener.h" #include "util.h" +using namespace std::chrono_literals; + // Class Declarations // ------------------ class FirstStageMount { @@ -49,11 +52,11 @@ class FirstStageMount { bool InitDevices(); protected: - void InitRequiredDevices(); - void InitVerityDevice(const std::string& verity_device); + bool InitRequiredDevices(); + bool InitVerityDevice(const std::string& verity_device); bool MountPartitions(); - virtual RegenerationAction UeventCallback(const Uevent& uevent); + virtual ListenerAction UeventCallback(const Uevent& uevent); // Pure virtual functions. virtual bool GetRequiredDevices() = 0; @@ -86,7 +89,7 @@ class FirstStageMountVBootV2 : public FirstStageMount { ~FirstStageMountVBootV2() override = default; protected: - RegenerationAction UeventCallback(const Uevent& uevent) override; + ListenerAction UeventCallback(const Uevent& uevent) override; bool GetRequiredDevices() override; bool SetUpDmVerity(fstab_rec* fstab_rec) override; bool InitAvbHandle(); @@ -141,49 +144,60 @@ bool FirstStageMount::DoFirstStageMount() { } bool FirstStageMount::InitDevices() { - if (!GetRequiredDevices()) return false; - - InitRequiredDevices(); - - // InitRequiredDevices() will remove found partitions from required_devices_partition_names_. - // So if it isn't empty here, it means some partitions are not found. - if (!required_devices_partition_names_.empty()) { - LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: " - << android::base::Join(required_devices_partition_names_, ", "); - return false; - } else { - return true; - } + return GetRequiredDevices() && InitRequiredDevices(); } // Creates devices with uevent->partition_name matching one in the member variable // required_devices_partition_names_. Found partitions will then be removed from it // for the subsequent member function to check which devices are NOT created. -void FirstStageMount::InitRequiredDevices() { +bool FirstStageMount::InitRequiredDevices() { if (required_devices_partition_names_.empty()) { - return; + return true; } if (need_dm_verity_) { const std::string dm_path = "/devices/virtual/misc/device-mapper"; - uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, - [this, &dm_path](const Uevent& uevent) { - if (uevent.path == dm_path) { - device_handler_.HandleDeviceEvent(uevent); - return RegenerationAction::kStop; - } - return RegenerationAction::kContinue; - }); + bool found = false; + auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) { + if (uevent.path == dm_path) { + device_handler_.HandleDeviceEvent(uevent); + found = true; + return ListenerAction::kStop; + } + return ListenerAction::kContinue; + }; + uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback); + if (!found) { + uevent_listener_.Poll(dm_callback, 10s); + } + if (!found) { + LOG(ERROR) << "device-mapper device not found"; + return false; + } } - uevent_listener_.RegenerateUevents( - [this](const Uevent& uevent) { return UeventCallback(uevent); }); + auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); }; + uevent_listener_.RegenerateUevents(uevent_callback); + + // UeventCallback() will remove found partitions from required_devices_partition_names_. + // So if it isn't empty here, it means some partitions are not found. + if (!required_devices_partition_names_.empty()) { + uevent_listener_.Poll(uevent_callback, 10s); + } + + if (!required_devices_partition_names_.empty()) { + LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: " + << android::base::Join(required_devices_partition_names_, ", "); + return false; + } + + return true; } -RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) { +ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) { // Ignores everything that is not a block device. if (uevent.subsystem != "block") { - return RegenerationAction::kContinue; + return ListenerAction::kContinue; } if (!uevent.partition_name.empty()) { @@ -192,34 +206,46 @@ RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) { // suffix when A/B is used. auto iter = required_devices_partition_names_.find(uevent.partition_name); if (iter != required_devices_partition_names_.end()) { - LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter; + LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter; required_devices_partition_names_.erase(iter); device_handler_.HandleDeviceEvent(uevent); if (required_devices_partition_names_.empty()) { - return RegenerationAction::kStop; + return ListenerAction::kStop; } else { - return RegenerationAction::kContinue; + return ListenerAction::kContinue; } } } // Not found a partition or find an unneeded partition, continue to find others. - return RegenerationAction::kContinue; + return ListenerAction::kContinue; } // Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX. -void FirstStageMount::InitVerityDevice(const std::string& verity_device) { +bool FirstStageMount::InitVerityDevice(const std::string& verity_device) { const std::string device_name(basename(verity_device.c_str())); const std::string syspath = "/sys/block/" + device_name; + bool found = false; - uevent_listener_.RegenerateUeventsForPath( - syspath, [&device_name, &verity_device, this](const Uevent& uevent) { - if (uevent.device_name == device_name) { - LOG(VERBOSE) << "Creating dm-verity device : " << verity_device; - device_handler_.HandleDeviceEvent(uevent); - return RegenerationAction::kStop; - } - return RegenerationAction::kContinue; - }); + auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) { + if (uevent.device_name == device_name) { + LOG(VERBOSE) << "Creating dm-verity device : " << verity_device; + device_handler_.HandleDeviceEvent(uevent); + found = true; + return ListenerAction::kStop; + } + return ListenerAction::kContinue; + }; + + uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback); + if (!found) { + uevent_listener_.Poll(verity_callback, 10s); + } + if (!found) { + LOG(ERROR) << "dm-verity device not found"; + return false; + } + + return true; } bool FirstStageMount::MountPartitions() { @@ -288,7 +314,7 @@ bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) { case FS_MGR_SETUP_VERITY_SUCCESS: // The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX". // Needs to create it because ueventd isn't started in init first stage. - InitVerityDevice(fstab_rec->blk_device); + return InitVerityDevice(fstab_rec->blk_device); break; default: return false; @@ -349,7 +375,7 @@ bool FirstStageMountVBootV2::GetRequiredDevices() { return true; } -RegenerationAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) { +ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) { // Check if this uevent corresponds to one of the required partitions and store its symlinks if // so, in order to create FsManagerAvbHandle later. // Note that the parent callback removes partitions from the list of required partitions diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index 01b825071..923fa8e8f 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp @@ -121,8 +121,8 @@ bool UeventListener::ReadUevent(Uevent* uevent) const { // make sure we don't overrun the socket's buffer. // -RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d, - RegenerateCallback callback) const { +ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d, + const ListenerCallback& callback) const { int dfd = dirfd(d); int fd = openat(dfd, "uevent", O_WRONLY); @@ -132,7 +132,7 @@ RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d, Uevent uevent; while (ReadUevent(&uevent)) { - if (callback(uevent) == RegenerationAction::kStop) return RegenerationAction::kStop; + if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop; } } @@ -147,49 +147,67 @@ RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d, if (d2 == 0) { close(fd); } else { - if (RegenerateUeventsForDir(d2.get(), callback) == RegenerationAction::kStop) { - return RegenerationAction::kStop; + if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) { + return ListenerAction::kStop; } } } // default is always to continue looking for uevents - return RegenerationAction::kContinue; + return ListenerAction::kContinue; } -RegenerationAction UeventListener::RegenerateUeventsForPath(const std::string& path, - RegenerateCallback callback) const { +ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path, + const ListenerCallback& callback) const { std::unique_ptr d(opendir(path.c_str()), closedir); - if (!d) return RegenerationAction::kContinue; + if (!d) return ListenerAction::kContinue; return RegenerateUeventsForDir(d.get(), callback); } const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"}; -void UeventListener::RegenerateUevents(RegenerateCallback callback) const { +void UeventListener::RegenerateUevents(const ListenerCallback& callback) const { for (const auto path : kRegenerationPaths) { - if (RegenerateUeventsForPath(path, callback) == RegenerationAction::kStop) return; + if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return; } } -void UeventListener::DoPolling(PollCallback callback) const { +void UeventListener::Poll(const ListenerCallback& callback, + const std::optional relative_timeout) const { + using namespace std::chrono; + pollfd ufd; ufd.events = POLLIN; ufd.fd = device_fd_; + auto start_time = steady_clock::now(); + while (true) { ufd.revents = 0; - int nr = poll(&ufd, 1, -1); - if (nr <= 0) { + + int timeout_ms = -1; + if (relative_timeout) { + auto now = steady_clock::now(); + auto time_elapsed = duration_cast(now - start_time); + if (time_elapsed > *relative_timeout) return; + + auto remaining_timeout = *relative_timeout - time_elapsed; + timeout_ms = remaining_timeout.count(); + } + + int nr = poll(&ufd, 1, timeout_ms); + if (nr == 0) return; + if (nr < 0) { + PLOG(ERROR) << "poll() of uevent socket failed, continuing"; continue; } if (ufd.revents & POLLIN) { - // We're non-blocking, so if we receive a poll event keep processing until there + // We're non-blocking, so if we receive a poll event keep processing until // we have exhausted all uevent messages. Uevent uevent; while (ReadUevent(&uevent)) { - callback(uevent); + if (callback(uevent) == ListenerAction::kStop) return; } } } diff --git a/init/uevent_listener.h b/init/uevent_listener.h index 8e6f3b40b..196468848 100644 --- a/init/uevent_listener.h +++ b/init/uevent_listener.h @@ -19,7 +19,9 @@ #include +#include #include +#include #include @@ -27,13 +29,12 @@ #define UEVENT_MSG_LEN 2048 -enum class RegenerationAction { +enum class ListenerAction { kStop = 0, // Stop regenerating uevents as we've handled the one(s) we're interested in. kContinue, // Continue regenerating uevents as we haven't seen the one(s) we're interested in. }; -using RegenerateCallback = std::function; -using PollCallback = std::function; +using ListenerCallback = std::function; extern const char* kRegenerationPaths[3]; @@ -41,14 +42,15 @@ class UeventListener { public: UeventListener(); - void RegenerateUevents(RegenerateCallback callback) const; - RegenerationAction RegenerateUeventsForPath(const std::string& path, - RegenerateCallback callback) const; - void DoPolling(PollCallback callback) const; + void RegenerateUevents(const ListenerCallback& callback) const; + ListenerAction RegenerateUeventsForPath(const std::string& path, + const ListenerCallback& callback) const; + void Poll(const ListenerCallback& callback, + const std::optional relative_timeout = {}) const; private: bool ReadUevent(Uevent* uevent) const; - RegenerationAction RegenerateUeventsForDir(DIR* d, RegenerateCallback callback) const; + ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const; android::base::unique_fd device_fd_; }; diff --git a/init/ueventd.cpp b/init/ueventd.cpp index 8cf932675..ff64e8eeb 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -138,7 +138,7 @@ void ColdBoot::RegenerateUevents() { HandleFirmwareEvent(uevent); uevent_queue_.emplace_back(std::move(uevent)); - return RegenerationAction::kContinue; + return ListenerAction::kContinue; }); } @@ -268,9 +268,10 @@ int ueventd_main(int argc, char** argv) { cold_boot.Run(); } - uevent_listener.DoPolling([&device_handler](const Uevent& uevent) { + uevent_listener.Poll([&device_handler](const Uevent& uevent) { HandleFirmwareEvent(uevent); device_handler.HandleDeviceEvent(uevent); + return ListenerAction::kContinue; }); return 0;