release-request-5bf29450-4eb0-4d71-a15a-d8858bf184d3-for-git_oc-release-4120128 snap-temp-L37600000076154351
Change-Id: Icfb38e46cb517b62b9af2c95c4bbc2afc4c56084
diff --git a/init/devices.cpp b/init/devices.cpp
index 39571ac..6f86662 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <poll.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -46,6 +47,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/list.h>
#include <cutils/uevent.h>
@@ -79,16 +81,8 @@
struct listnode plist;
};
-struct platform_node {
- char *name;
- char *path;
- int path_len;
- struct listnode list;
-};
-
static list_declare(sys_perms);
static list_declare(dev_perms);
-static list_declare(platform_names);
int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid, unsigned int gid,
@@ -286,77 +280,37 @@
}
}
-static void add_platform_device(const char *path)
-{
- int path_len = strlen(path);
- struct platform_node *bus;
- const char *name = path;
+// Given a path that may start with a platform device, find the parent platform device by finding a
+// parent directory with a 'subsystem' symlink that points to the platform bus.
+// If it doesn't start with a platform device, return false
+bool FindPlatformDevice(std::string path, std::string* platform_device_path) {
+ platform_device_path->clear();
- if (!strncmp(path, "/devices/", 9)) {
- name += 9;
- if (!strncmp(name, "platform/", 9))
- name += 9;
- }
+ static const std::string kSysfsMountPoint = "/sys";
- LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
+ // Uevents don't contain the mount point, so we need to add it here.
+ path.insert(0, kSysfsMountPoint);
- bus = (platform_node*) calloc(1, sizeof(struct platform_node));
- bus->path = strdup(path);
- bus->path_len = path_len;
- bus->name = bus->path + (name - path);
- list_add_tail(&platform_names, &bus->list);
-}
+ std::string directory = android::base::Dirname(path);
-/*
- * given a path that may start with a platform device, find the length of the
- * platform device prefix. If it doesn't start with a platform device, return
- * 0.
- */
-static struct platform_node *find_platform_device(const char *path)
-{
- int path_len = strlen(path);
- struct listnode *node;
- struct platform_node *bus;
-
- list_for_each_reverse(node, &platform_names) {
- bus = node_to_item(node, struct platform_node, list);
- if ((bus->path_len < path_len) &&
- (path[bus->path_len] == '/') &&
- !strncmp(path, bus->path, bus->path_len))
- return bus;
- }
-
- return NULL;
-}
-
-static void remove_platform_device(const char *path)
-{
- struct listnode *node;
- struct platform_node *bus;
-
- list_for_each_reverse(node, &platform_names) {
- bus = node_to_item(node, struct platform_node, list);
- if (!strcmp(path, bus->path)) {
- LOG(INFO) << "removing platform device " << bus->name;
- free(bus->path);
- list_remove(node);
- free(bus);
- return;
+ while (directory != "/" && directory != ".") {
+ std::string subsystem_link_path;
+ if (android::base::Realpath(directory + "/subsystem", &subsystem_link_path) &&
+ subsystem_link_path == kSysfsMountPoint + "/bus/platform") {
+ // We need to remove the mount point that we added above before returning.
+ directory.erase(0, kSysfsMountPoint.size());
+ *platform_device_path = directory;
+ return true;
}
- }
-}
-static void destroy_platform_devices() {
- struct listnode* node;
- struct listnode* n;
- struct platform_node* bus;
+ auto last_slash = path.rfind('/');
+ if (last_slash == std::string::npos) return false;
- list_for_each_safe(node, n, &platform_names) {
- list_remove(node);
- bus = node_to_item(node, struct platform_node, list);
- free(bus->path);
- free(bus);
+ path.erase(last_slash);
+ directory = android::base::Dirname(path);
}
+
+ return false;
}
/* Given a path that may start with a PCI device, populate the supplied buffer
@@ -480,11 +434,9 @@
char **links;
int link_num = 0;
int width;
- struct platform_node *pdev;
- pdev = find_platform_device(uevent->path);
- if (!pdev)
- return NULL;
+ std::string platform_device;
+ if (!FindPlatformDevice(uevent->path, &platform_device)) return nullptr;
links = (char**) malloc(sizeof(char *) * 2);
if (!links)
@@ -492,7 +444,7 @@
memset(links, 0, sizeof(char *) * 2);
/* skip "/devices/platform/<driver>" */
- parent = strchr(uevent->path + pdev->path_len, '/');
+ parent = strchr(uevent->path + platform_device.size(), '/');
if (!parent)
goto err;
@@ -527,8 +479,6 @@
}
char** get_block_device_symlinks(struct uevent* uevent) {
- const char *device;
- struct platform_node *pdev;
const char *slash;
const char *type;
char buf[256];
@@ -536,9 +486,18 @@
int link_num = 0;
char *p;
- pdev = find_platform_device(uevent->path);
- if (pdev) {
- device = pdev->name;
+ std::string device;
+ if (FindPlatformDevice(uevent->path, &device)) {
+ // Skip /devices/platform or /devices/ if present
+ static const std::string devices_platform_prefix = "/devices/platform/";
+ static const std::string devices_prefix = "/devices/";
+
+ if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
+ device = device.substr(devices_platform_prefix.length());
+ } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
+ device = device.substr(devices_prefix.length());
+ }
+
type = "platform";
} else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
device = buf;
@@ -557,7 +516,7 @@
LOG(VERBOSE) << "found " << type << " device " << device;
- snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
+ snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device.c_str());
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
@@ -635,16 +594,6 @@
}
}
-static void handle_platform_device_event(struct uevent *uevent)
-{
- const char *path = uevent->path;
-
- if (!strcmp(uevent->action, "add"))
- add_platform_device(path);
- else if (!strcmp(uevent->action, "remove"))
- remove_platform_device(path);
-}
-
static const char *parse_device_name(struct uevent *uevent, unsigned int len)
{
const char *name;
@@ -824,8 +773,6 @@
if (!strncmp(uevent->subsystem, "block", 5)) {
handle_block_device_event(uevent);
- } else if (!strncmp(uevent->subsystem, "platform", 8)) {
- handle_platform_device_event(uevent);
} else {
handle_generic_device_event(uevent);
}
@@ -1078,11 +1025,41 @@
}
void device_close() {
- destroy_platform_devices();
device_fd.reset();
selinux_status_close();
}
-int get_device_fd() {
- return device_fd;
+void device_poll(const coldboot_callback& callback,
+ const std::optional<std::chrono::milliseconds> relative_timeout) {
+ 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 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) {
+ continue;
+ }
+ if (ufd.revents & POLLIN) {
+ auto ret = handle_device_fd(callback);
+ if (should_stop_coldboot(ret)) return;
+ }
+ }
}
diff --git a/init/devices.h b/init/devices.h
index 3f2cde4..62aef2e 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,9 +17,12 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
-#include <functional>
#include <sys/stat.h>
+#include <chrono>
+#include <functional>
+#include <optional>
+
enum coldboot_action_t {
// coldboot continues without creating the device for the uevent
COLDBOOT_CONTINUE = 0,
@@ -53,8 +56,10 @@
mode_t perm, unsigned int uid,
unsigned int gid, unsigned short prefix,
unsigned short wildcard);
-int get_device_fd();
char** get_block_device_symlinks(struct uevent* uevent);
+void device_poll(const coldboot_callback& callback = nullptr,
+ const std::optional<std::chrono::milliseconds> relative_timeout = {});
+
#endif /* _INIT_DEVICES_H */
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index bcc8d1b..9425027 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include <chrono>
#include <memory>
#include <set>
#include <string>
@@ -33,6 +34,8 @@
#include "fs_mgr_avb.h"
#include "util.h"
+using namespace std::chrono_literals;
+
// Class Declarations
// ------------------
class FirstStageMount {
@@ -47,8 +50,8 @@
bool InitDevices();
protected:
- void InitRequiredDevices();
- void InitVerityDevice(const std::string& verity_device);
+ bool InitRequiredDevices();
+ bool InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
virtual coldboot_action_t ColdbootCallback(uevent* uevent);
@@ -139,50 +142,56 @@
return true;
}
-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;
- }
-}
+bool FirstStageMount::InitDevices() { 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";
- device_init(("/sys" + dm_path).c_str(), [&dm_path](uevent* uevent) -> coldboot_action_t {
- if (uevent->path && uevent->path == dm_path) return COLDBOOT_STOP;
+ bool found = false;
+ auto dm_callback = [&dm_path, &found](uevent* uevent) -> coldboot_action_t {
+ if (uevent->path && uevent->path == dm_path) {
+ found = true;
+ return COLDBOOT_STOP;
+ }
return COLDBOOT_CONTINUE; // dm_path not found, continue to find it.
- });
+ };
+ device_init(("/sys" + dm_path).c_str(), dm_callback);
+ if (!found) {
+ device_poll(dm_callback, 10s);
+ }
+ if (!found) {
+ LOG(ERROR) << "device-mapper device not found";
+ return false;
+ }
}
- device_init(nullptr,
- [this](uevent* uevent) -> coldboot_action_t { return ColdbootCallback(uevent); });
+ auto uevent_callback = [this](uevent* uevent) -> coldboot_action_t {
+ return ColdbootCallback(uevent);
+ };
+
+ device_init(nullptr, uevent_callback);
+ if (!required_devices_partition_names_.empty()) {
+ device_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;
+ }
device_close();
+ return true;
}
coldboot_action_t FirstStageMount::ColdbootCallback(uevent* uevent) {
- // We need platform devices to create symlinks.
- if (!strncmp(uevent->subsystem, "platform", 8)) {
- return COLDBOOT_CREATE;
- }
-
// Ignores everything that is not a block device.
if (strncmp(uevent->subsystem, "block", 5)) {
return COLDBOOT_CONTINUE;
@@ -208,18 +217,30 @@
}
// 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;
- device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+ auto verity_callback = [&](uevent* uevent) -> coldboot_action_t {
if (uevent->device_name && uevent->device_name == device_name) {
LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+ found = true;
return COLDBOOT_STOP;
}
return COLDBOOT_CONTINUE;
- });
+ };
+
+ device_init(syspath.c_str(), verity_callback);
+ if (!found) {
+ device_poll(verity_callback, 10s);
+ }
+ if (!found) {
+ LOG(ERROR) << "dm-verity device not found";
+ return false;
+ }
device_close();
+ return true;
}
bool FirstStageMount::MountPartitions() {
@@ -285,7 +306,7 @@
} else if (ret == 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);
} else {
return false;
}
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index f27be64..d0b7b8e 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -17,7 +17,6 @@
#include <ctype.h>
#include <fcntl.h>
#include <grp.h>
-#include <poll.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
@@ -76,20 +75,7 @@
device_init();
- pollfd ufd;
- ufd.events = POLLIN;
- ufd.fd = get_device_fd();
-
- while (true) {
- ufd.revents = 0;
- int nr = poll(&ufd, 1, -1);
- if (nr <= 0) {
- continue;
- }
- if (ufd.revents & POLLIN) {
- handle_device_fd();
- }
- }
+ device_poll();
return 0;
}