Merge "init: poll in first stage mount if required devices are not found"
am: 20e9312344
Change-Id: I3055e999ff976662da18818756fc6ed07b09f360
This commit is contained in:
commit
492a595091
4 changed files with 120 additions and 73 deletions
|
|
@ -19,6 +19,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -35,6 +36,8 @@
|
||||||
#include "uevent_listener.h"
|
#include "uevent_listener.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
// Class Declarations
|
// Class Declarations
|
||||||
// ------------------
|
// ------------------
|
||||||
class FirstStageMount {
|
class FirstStageMount {
|
||||||
|
|
@ -49,11 +52,11 @@ class FirstStageMount {
|
||||||
bool InitDevices();
|
bool InitDevices();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitRequiredDevices();
|
bool InitRequiredDevices();
|
||||||
void InitVerityDevice(const std::string& verity_device);
|
bool InitVerityDevice(const std::string& verity_device);
|
||||||
bool MountPartitions();
|
bool MountPartitions();
|
||||||
|
|
||||||
virtual RegenerationAction UeventCallback(const Uevent& uevent);
|
virtual ListenerAction UeventCallback(const Uevent& uevent);
|
||||||
|
|
||||||
// Pure virtual functions.
|
// Pure virtual functions.
|
||||||
virtual bool GetRequiredDevices() = 0;
|
virtual bool GetRequiredDevices() = 0;
|
||||||
|
|
@ -86,7 +89,7 @@ class FirstStageMountVBootV2 : public FirstStageMount {
|
||||||
~FirstStageMountVBootV2() override = default;
|
~FirstStageMountVBootV2() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RegenerationAction UeventCallback(const Uevent& uevent) override;
|
ListenerAction UeventCallback(const Uevent& uevent) override;
|
||||||
bool GetRequiredDevices() override;
|
bool GetRequiredDevices() override;
|
||||||
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
|
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
|
||||||
bool InitAvbHandle();
|
bool InitAvbHandle();
|
||||||
|
|
@ -141,49 +144,60 @@ bool FirstStageMount::DoFirstStageMount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FirstStageMount::InitDevices() {
|
bool FirstStageMount::InitDevices() {
|
||||||
if (!GetRequiredDevices()) return false;
|
return GetRequiredDevices() && InitRequiredDevices();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates devices with uevent->partition_name matching one in the member variable
|
// Creates devices with uevent->partition_name matching one in the member variable
|
||||||
// required_devices_partition_names_. Found partitions will then be removed from it
|
// required_devices_partition_names_. Found partitions will then be removed from it
|
||||||
// for the subsequent member function to check which devices are NOT created.
|
// for the subsequent member function to check which devices are NOT created.
|
||||||
void FirstStageMount::InitRequiredDevices() {
|
bool FirstStageMount::InitRequiredDevices() {
|
||||||
if (required_devices_partition_names_.empty()) {
|
if (required_devices_partition_names_.empty()) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_dm_verity_) {
|
if (need_dm_verity_) {
|
||||||
const std::string dm_path = "/devices/virtual/misc/device-mapper";
|
const std::string dm_path = "/devices/virtual/misc/device-mapper";
|
||||||
uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path,
|
bool found = false;
|
||||||
[this, &dm_path](const Uevent& uevent) {
|
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
|
||||||
if (uevent.path == dm_path) {
|
if (uevent.path == dm_path) {
|
||||||
device_handler_.HandleDeviceEvent(uevent);
|
device_handler_.HandleDeviceEvent(uevent);
|
||||||
return RegenerationAction::kStop;
|
found = true;
|
||||||
}
|
return ListenerAction::kStop;
|
||||||
return RegenerationAction::kContinue;
|
}
|
||||||
});
|
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(
|
auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
|
||||||
[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.
|
// Ignores everything that is not a block device.
|
||||||
if (uevent.subsystem != "block") {
|
if (uevent.subsystem != "block") {
|
||||||
return RegenerationAction::kContinue;
|
return ListenerAction::kContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uevent.partition_name.empty()) {
|
if (!uevent.partition_name.empty()) {
|
||||||
|
|
@ -192,34 +206,46 @@ RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) {
|
||||||
// suffix when A/B is used.
|
// suffix when A/B is used.
|
||||||
auto iter = required_devices_partition_names_.find(uevent.partition_name);
|
auto iter = required_devices_partition_names_.find(uevent.partition_name);
|
||||||
if (iter != required_devices_partition_names_.end()) {
|
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);
|
required_devices_partition_names_.erase(iter);
|
||||||
device_handler_.HandleDeviceEvent(uevent);
|
device_handler_.HandleDeviceEvent(uevent);
|
||||||
if (required_devices_partition_names_.empty()) {
|
if (required_devices_partition_names_.empty()) {
|
||||||
return RegenerationAction::kStop;
|
return ListenerAction::kStop;
|
||||||
} else {
|
} else {
|
||||||
return RegenerationAction::kContinue;
|
return ListenerAction::kContinue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not found a partition or find an unneeded partition, continue to find others.
|
// 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.
|
// 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 device_name(basename(verity_device.c_str()));
|
||||||
const std::string syspath = "/sys/block/" + device_name;
|
const std::string syspath = "/sys/block/" + device_name;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
uevent_listener_.RegenerateUeventsForPath(
|
auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
|
||||||
syspath, [&device_name, &verity_device, this](const Uevent& uevent) {
|
if (uevent.device_name == device_name) {
|
||||||
if (uevent.device_name == device_name) {
|
LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
|
||||||
LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
|
device_handler_.HandleDeviceEvent(uevent);
|
||||||
device_handler_.HandleDeviceEvent(uevent);
|
found = true;
|
||||||
return RegenerationAction::kStop;
|
return ListenerAction::kStop;
|
||||||
}
|
}
|
||||||
return RegenerationAction::kContinue;
|
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() {
|
bool FirstStageMount::MountPartitions() {
|
||||||
|
|
@ -285,7 +311,7 @@ bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
|
||||||
} else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
|
} else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
|
||||||
// The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
|
// 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.
|
// Needs to create it because ueventd isn't started in init first stage.
|
||||||
InitVerityDevice(fstab_rec->blk_device);
|
return InitVerityDevice(fstab_rec->blk_device);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +371,7 @@ bool FirstStageMountVBootV2::GetRequiredDevices() {
|
||||||
return true;
|
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
|
// Check if this uevent corresponds to one of the required partitions and store its symlinks if
|
||||||
// so, in order to create FsManagerAvbHandle later.
|
// so, in order to create FsManagerAvbHandle later.
|
||||||
// Note that the parent callback removes partitions from the list of required partitions
|
// Note that the parent callback removes partitions from the list of required partitions
|
||||||
|
|
|
||||||
|
|
@ -121,8 +121,8 @@ bool UeventListener::ReadUevent(Uevent* uevent) const {
|
||||||
// make sure we don't overrun the socket's buffer.
|
// make sure we don't overrun the socket's buffer.
|
||||||
//
|
//
|
||||||
|
|
||||||
RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
|
ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
|
||||||
RegenerateCallback callback) const {
|
const ListenerCallback& callback) const {
|
||||||
int dfd = dirfd(d);
|
int dfd = dirfd(d);
|
||||||
|
|
||||||
int fd = openat(dfd, "uevent", O_WRONLY);
|
int fd = openat(dfd, "uevent", O_WRONLY);
|
||||||
|
|
@ -132,7 +132,7 @@ RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
|
||||||
|
|
||||||
Uevent uevent;
|
Uevent uevent;
|
||||||
while (ReadUevent(&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) {
|
if (d2 == 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
} else {
|
} else {
|
||||||
if (RegenerateUeventsForDir(d2.get(), callback) == RegenerationAction::kStop) {
|
if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
|
||||||
return RegenerationAction::kStop;
|
return ListenerAction::kStop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// default is always to continue looking for uevents
|
// default is always to continue looking for uevents
|
||||||
return RegenerationAction::kContinue;
|
return ListenerAction::kContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegenerationAction UeventListener::RegenerateUeventsForPath(const std::string& path,
|
ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
|
||||||
RegenerateCallback callback) const {
|
const ListenerCallback& callback) const {
|
||||||
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
|
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
|
||||||
if (!d) return RegenerationAction::kContinue;
|
if (!d) return ListenerAction::kContinue;
|
||||||
|
|
||||||
return RegenerateUeventsForDir(d.get(), callback);
|
return RegenerateUeventsForDir(d.get(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
|
static 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) {
|
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<std::chrono::milliseconds> relative_timeout) const {
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
pollfd ufd;
|
pollfd ufd;
|
||||||
ufd.events = POLLIN;
|
ufd.events = POLLIN;
|
||||||
ufd.fd = device_fd_;
|
ufd.fd = device_fd_;
|
||||||
|
|
||||||
|
auto start_time = steady_clock::now();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ufd.revents = 0;
|
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<milliseconds>(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;
|
continue;
|
||||||
}
|
}
|
||||||
if (ufd.revents & POLLIN) {
|
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.
|
// we have exhausted all uevent messages.
|
||||||
Uevent uevent;
|
Uevent uevent;
|
||||||
while (ReadUevent(&uevent)) {
|
while (ReadUevent(&uevent)) {
|
||||||
callback(uevent);
|
if (callback(uevent) == ListenerAction::kStop) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <android-base/unique_fd.h>
|
#include <android-base/unique_fd.h>
|
||||||
|
|
||||||
|
|
@ -27,26 +29,26 @@
|
||||||
|
|
||||||
#define UEVENT_MSG_LEN 2048
|
#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.
|
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.
|
kContinue, // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
|
||||||
};
|
};
|
||||||
|
|
||||||
using RegenerateCallback = std::function<RegenerationAction(const Uevent&)>;
|
using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
|
||||||
using PollCallback = std::function<void(const Uevent&)>;
|
|
||||||
|
|
||||||
class UeventListener {
|
class UeventListener {
|
||||||
public:
|
public:
|
||||||
UeventListener();
|
UeventListener();
|
||||||
|
|
||||||
void RegenerateUevents(RegenerateCallback callback) const;
|
void RegenerateUevents(const ListenerCallback& callback) const;
|
||||||
RegenerationAction RegenerateUeventsForPath(const std::string& path,
|
ListenerAction RegenerateUeventsForPath(const std::string& path,
|
||||||
RegenerateCallback callback) const;
|
const ListenerCallback& callback) const;
|
||||||
void DoPolling(PollCallback callback) const;
|
void Poll(const ListenerCallback& callback,
|
||||||
|
const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadUevent(Uevent* uevent) const;
|
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_;
|
android::base::unique_fd device_fd_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ void ColdBoot::RegenerateUevents() {
|
||||||
HandleFirmwareEvent(uevent);
|
HandleFirmwareEvent(uevent);
|
||||||
|
|
||||||
uevent_queue_.emplace_back(std::move(uevent));
|
uevent_queue_.emplace_back(std::move(uevent));
|
||||||
return RegenerationAction::kContinue;
|
return ListenerAction::kContinue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,9 +266,10 @@ int ueventd_main(int argc, char** argv) {
|
||||||
cold_boot.Run();
|
cold_boot.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
uevent_listener.DoPolling([&device_handler](const Uevent& uevent) {
|
uevent_listener.Poll([&device_handler](const Uevent& uevent) {
|
||||||
HandleFirmwareEvent(uevent);
|
HandleFirmwareEvent(uevent);
|
||||||
device_handler.HandleDeviceEvent(uevent);
|
device_handler.HandleDeviceEvent(uevent);
|
||||||
|
return ListenerAction::kContinue;
|
||||||
});
|
});
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue