Merge changes from topic 'eng_first_stage_mount' am: b7e2f272ee

am: e5341cf56a

Change-Id: I285217db1c18adfcc10d31280c1ec55d80052e43
This commit is contained in:
Sandeep Patil 2017-06-22 00:08:17 +00:00 committed by android-build-merger
commit 91b5f4b172
10 changed files with 189 additions and 194 deletions

View file

@ -847,7 +847,9 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
} }
} else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) { } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true); int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { if (__android_log_is_debuggable() &&
(rc == FS_MGR_SETUP_VERITY_DISABLED ||
rc == FS_MGR_SETUP_VERITY_SKIPPED)) {
LINFO << "Verity disabled"; LINFO << "Verity disabled";
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
LERROR << "Could not set up verified partition, skipping!"; LERROR << "Could not set up verified partition, skipping!";
@ -1061,7 +1063,9 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
} }
} else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) { } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true); int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { if (__android_log_is_debuggable() &&
(rc == FS_MGR_SETUP_VERITY_DISABLED ||
rc == FS_MGR_SETUP_VERITY_SKIPPED)) {
LINFO << "Verity disabled"; LINFO << "Verity disabled";
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
LERROR << "Could not set up verified partition, skipping!"; LERROR << "Could not set up verified partition, skipping!";

View file

@ -766,7 +766,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
// setup is needed at all. // setup is needed at all.
if (!is_device_secure()) { if (!is_device_secure()) {
LINFO << "Verity setup skipped for " << mount_point; LINFO << "Verity setup skipped for " << mount_point;
return FS_MGR_SETUP_VERITY_SUCCESS; return FS_MGR_SETUP_VERITY_SKIPPED;
} }
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE, if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,

View file

@ -143,6 +143,7 @@ int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer); int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
#define FS_MGR_SETUP_VERITY_DISABLED (-2) #define FS_MGR_SETUP_VERITY_DISABLED (-2)
#define FS_MGR_SETUP_VERITY_FAIL (-1) #define FS_MGR_SETUP_VERITY_FAIL (-1)
#define FS_MGR_SETUP_VERITY_SUCCESS 0 #define FS_MGR_SETUP_VERITY_SUCCESS 0

View file

@ -147,21 +147,34 @@ void SysfsPermissions::SetPermissions(const std::string& path) const {
} }
} }
// Given a path that may start with a platform device, find the length of the // Given a path that may start with a platform device, find the parent platform device by finding a
// platform device prefix. If it doesn't start with a platform device, return false // parent directory with a 'subsystem' symlink that points to the platform bus.
bool PlatformDeviceList::Find(const std::string& path, std::string* out_path) const { // If it doesn't start with a platform device, return false
out_path->clear(); bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
// platform_devices is searched backwards, since parents are added before their children, platform_device_path->clear();
// and we want to match as deep of a child as we can.
for (auto it = platform_devices_.crbegin(); it != platform_devices_.crend(); ++it) { // Uevents don't contain the mount point, so we need to add it here.
auto platform_device_path_length = it->length(); path.insert(0, sysfs_mount_point_);
if (platform_device_path_length < path.length() &&
path[platform_device_path_length] == '/' && std::string directory = android::base::Dirname(path);
android::base::StartsWith(path, it->c_str())) {
*out_path = *it; while (directory != "/" && directory != ".") {
std::string subsystem_link_path;
if (android::base::Realpath(directory + "/subsystem", &subsystem_link_path) &&
subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
// We need to remove the mount point that we added above before returning.
directory.erase(0, sysfs_mount_point_.size());
*platform_device_path = directory;
return true; return true;
} }
auto last_slash = path.rfind('/');
if (last_slash == std::string::npos) return false;
path.erase(last_slash);
directory = android::base::Dirname(path);
} }
return false; return false;
} }
@ -258,7 +271,7 @@ out:
std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const { std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
std::string parent_device; std::string parent_device;
if (!platform_devices_.Find(uevent.path, &parent_device)) return {}; if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
// skip path to the parent driver // skip path to the parent driver
std::string path = uevent.path.substr(parent_device.length()); std::string path = uevent.path.substr(parent_device.length());
@ -316,7 +329,7 @@ std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev
std::string device; std::string device;
std::string type; std::string type;
if (platform_devices_.Find(uevent.path, &device)) { if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present // Skip /devices/platform or /devices/ if present
static const std::string devices_platform_prefix = "/devices/platform/"; static const std::string devices_platform_prefix = "/devices/platform/";
static const std::string devices_prefix = "/devices/"; static const std::string devices_prefix = "/devices/";
@ -388,14 +401,6 @@ void DeviceHandler::HandleDevice(const std::string& action, const std::string& d
} }
} }
void DeviceHandler::HandlePlatformDeviceEvent(const Uevent& uevent) {
if (uevent.action == "add") {
platform_devices_.Add(uevent.path);
} else if (uevent.action == "remove") {
platform_devices_.Remove(uevent.path);
}
}
void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const { void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
// if it's not a /dev device, nothing to do // if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return; if (uevent.major < 0 || uevent.minor < 0) return;
@ -458,8 +463,6 @@ void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
if (uevent.subsystem == "block") { if (uevent.subsystem == "block") {
HandleBlockDeviceEvent(uevent); HandleBlockDeviceEvent(uevent);
} else if (uevent.subsystem == "platform") {
HandlePlatformDeviceEvent(uevent);
} else { } else {
HandleGenericDeviceEvent(uevent); HandleGenericDeviceEvent(uevent);
} }
@ -472,7 +475,8 @@ DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
sysfs_permissions_(std::move(sysfs_permissions)), sysfs_permissions_(std::move(sysfs_permissions)),
subsystems_(std::move(subsystems)), subsystems_(std::move(subsystems)),
sehandle_(selinux_android_file_context_handle()), sehandle_(selinux_android_file_context_handle()),
skip_restorecon_(skip_restorecon) {} skip_restorecon_(skip_restorecon),
sysfs_mount_point_("/sys") {}
DeviceHandler::DeviceHandler() DeviceHandler::DeviceHandler()
: DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},

View file

@ -93,20 +93,6 @@ class Subsystem {
DevnameSource devname_source_; DevnameSource devname_source_;
}; };
class PlatformDeviceList {
public:
void Add(const std::string& path) { platform_devices_.emplace_back(path); }
void Remove(const std::string& path) {
auto it = std::find(platform_devices_.begin(), platform_devices_.end(), path);
if (it != platform_devices_.end()) platform_devices_.erase(it);
}
bool Find(const std::string& path, std::string* out_path) const;
auto size() const { return platform_devices_.size(); }
private:
std::vector<std::string> platform_devices_;
};
class DeviceHandler { class DeviceHandler {
public: public:
friend class DeviceHandlerTester; friend class DeviceHandlerTester;
@ -119,16 +105,11 @@ class DeviceHandler {
void HandleDeviceEvent(const Uevent& uevent); void HandleDeviceEvent(const Uevent& uevent);
void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
void HandlePlatformDeviceEvent(const Uevent& uevent);
void HandleBlockDeviceEvent(const Uevent& uevent) const;
void HandleGenericDeviceEvent(const Uevent& uevent) const;
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const; std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
void set_skip_restorecon(bool value) { skip_restorecon_ = value; } void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
private: private:
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions( std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
const std::string& path, const std::vector<std::string>& links) const; const std::string& path, const std::vector<std::string>& links) const;
void MakeDevice(const std::string& path, int block, int major, int minor, void MakeDevice(const std::string& path, int block, int major, int minor,
@ -136,13 +117,17 @@ class DeviceHandler {
std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const; std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
void HandleDevice(const std::string& action, const std::string& devpath, int block, int major, void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
int minor, const std::vector<std::string>& links) const; int minor, const std::vector<std::string>& links) const;
void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
void HandleBlockDeviceEvent(const Uevent& uevent) const;
void HandleGenericDeviceEvent(const Uevent& uevent) const;
std::vector<Permissions> dev_permissions_; std::vector<Permissions> dev_permissions_;
std::vector<SysfsPermissions> sysfs_permissions_; std::vector<SysfsPermissions> sysfs_permissions_;
std::vector<Subsystem> subsystems_; std::vector<Subsystem> subsystems_;
PlatformDeviceList platform_devices_;
selabel_handle* sehandle_; selabel_handle* sehandle_;
bool skip_restorecon_; bool skip_restorecon_;
std::string sysfs_mount_point_;
}; };
// Exposed for testing // Exposed for testing

View file

@ -16,33 +16,29 @@
#include "devices.h" #include "devices.h"
#include <string>
#include <vector>
#include <android-base/scopeguard.h> #include <android-base/scopeguard.h>
#include <android-base/test_utils.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "util.h"
using namespace std::string_literals;
class DeviceHandlerTester { class DeviceHandlerTester {
public: public:
void AddPlatformDevice(const std::string& path) { void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
Uevent uevent = {
.action = "add", .subsystem = "platform", .path = path,
};
device_handler_.HandlePlatformDeviceEvent(uevent);
}
void RemovePlatformDevice(const std::string& path) {
Uevent uevent = {
.action = "remove", .subsystem = "platform", .path = path,
};
device_handler_.HandlePlatformDeviceEvent(uevent);
}
void TestGetSymlinks(const std::string& platform_device_name, const Uevent& uevent,
const std::vector<std::string> expected_links, bool block) { const std::vector<std::string> expected_links, bool block) {
AddPlatformDevice(platform_device_name); TemporaryDir fake_sys_root;
auto platform_device_remover = android::base::make_scope_guard( device_handler_.sysfs_mount_point_ = fake_sys_root.path;
[this, &platform_device_name]() { RemovePlatformDevice(platform_device_name); });
std::string platform_device_dir = fake_sys_root.path + platform_device;
mkdir_recursive(platform_device_dir, 0777, nullptr);
std::string platform_bus = fake_sys_root.path + "/bus/platform"s;
mkdir_recursive(platform_bus, 0777, nullptr);
symlink(platform_bus.c_str(), (platform_device_dir + "/subsystem").c_str());
mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
std::vector<std::string> result; std::vector<std::string> result;
if (block) { if (block) {
@ -65,30 +61,6 @@ class DeviceHandlerTester {
DeviceHandler device_handler_; DeviceHandler device_handler_;
}; };
TEST(device_handler, PlatformDeviceList) {
PlatformDeviceList platform_device_list;
platform_device_list.Add("/devices/platform/some_device_name");
platform_device_list.Add("/devices/platform/some_device_name/longer");
platform_device_list.Add("/devices/platform/other_device_name");
EXPECT_EQ(3U, platform_device_list.size());
std::string out_path;
EXPECT_FALSE(platform_device_list.Find("/devices/platform/not_found", &out_path));
EXPECT_EQ("", out_path);
EXPECT_FALSE(platform_device_list.Find("/devices/platform/some_device_name_with_same_prefix",
&out_path));
EXPECT_TRUE(platform_device_list.Find("/devices/platform/some_device_name/longer/longer_child",
&out_path));
EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
EXPECT_TRUE(
platform_device_list.Find("/devices/platform/some_device_name/other_child", &out_path));
EXPECT_EQ("/devices/platform/some_device_name", out_path);
}
TEST(device_handler, get_character_device_symlinks_success) { TEST(device_handler, get_character_device_symlinks_success) {
const char* platform_device = "/devices/platform/some_device_name"; const char* platform_device = "/devices/platform/some_device_name";
Uevent uevent = { Uevent uevent = {

View file

@ -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,55 +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) {
// We need platform devices to create symlinks.
if (uevent.subsystem == "platform") {
device_handler_.HandleDeviceEvent(uevent);
return RegenerationAction::kContinue;
}
// 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()) {
@ -198,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() {
@ -286,13 +306,17 @@ bool FirstStageMountVBootV1::GetRequiredDevices() {
bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) { bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_verified(fstab_rec)) { if (fs_mgr_is_verified(fstab_rec)) {
int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */); int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */);
if (ret == FS_MGR_SETUP_VERITY_DISABLED) { switch (ret) {
LOG(INFO) << "Verity disabled for '" << fstab_rec->mount_point << "'"; case FS_MGR_SETUP_VERITY_SKIPPED:
} else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) { case FS_MGR_SETUP_VERITY_DISABLED:
LOG(INFO) << "Verity disabled/skipped for '" << fstab_rec->mount_point << "'";
break;
case 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 { break;
default:
return false; return false;
} }
} }
@ -351,7 +375,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

View file

@ -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;
} }
} }
} }

View file

@ -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_;
}; };

View file

@ -128,15 +128,7 @@ class ColdBoot {
void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) { void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) { for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
auto& uevent = uevent_queue_[i]; auto& uevent = uevent_queue_[i];
if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") { device_handler_.HandleDeviceEvent(uevent);
device_handler_.FixupSysPermissions(uevent.path, uevent.subsystem);
}
if (uevent.subsystem == "block") {
device_handler_.HandleBlockDeviceEvent(uevent);
} else {
device_handler_.HandleGenericDeviceEvent(uevent);
}
} }
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
@ -145,16 +137,8 @@ void ColdBoot::RegenerateUevents() {
uevent_listener_.RegenerateUevents([this](const Uevent& uevent) { uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
HandleFirmwareEvent(uevent); HandleFirmwareEvent(uevent);
// This is the one mutable part of DeviceHandler, in which platform devices are
// added to a vector for later reference. Since there is no communication after
// fork()'ing subprocess handlers, all platform devices must be in the vector before
// we fork, and therefore they must be handled in this loop.
if (uevent.subsystem == "platform") {
device_handler_.HandlePlatformDeviceEvent(uevent);
}
uevent_queue_.emplace_back(std::move(uevent)); uevent_queue_.emplace_back(std::move(uevent));
return RegenerationAction::kContinue; return ListenerAction::kContinue;
}); });
} }
@ -282,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;