ueventd: convert platform_names from C list to std::vector
Also simplify this code a bit.
There's only one consumer that removes the /devices/platform prefix,
so have them handle it instead of storing two copies of the string.
Remove an unneeded search for '/' in get_character_device_symlinks()
as a / will always be the next character after a parent path, by
nature of FindPlatformDevice().
Test: boot bullhead
Test: init unit tests
Change-Id: I9d0482d137b1342ae7509ae993ff99198be814f0
diff --git a/init/devices.cpp b/init/devices.cpp
index 92eb6cf..ad313a0 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -76,16 +76,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,
@@ -270,74 +262,25 @@
}
}
-void add_platform_device(const char* path) {
- int path_len = strlen(path);
- struct platform_node *bus;
- const char *name = path;
+// TODO: Move this to be a member variable of a future devices class.
+std::vector<std::string> platform_devices;
- if (!strncmp(path, "/devices/", 9)) {
- name += 9;
- if (!strncmp(name, "platform/", 9))
- name += 9;
- }
-
- LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
-
- 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);
-}
-
-/*
- * 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;
-}
-
-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;
+// 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 false
+bool find_platform_device(const std::string& path, std::string* out_path) {
+ out_path->clear();
+ // platform_devices is searched backwards, since parents are added before their children,
+ // and we want to match as deep of a child as we can.
+ for (auto it = platform_devices.rbegin(); it != platform_devices.rend(); ++it) {
+ auto platform_device_path_length = it->length();
+ if (platform_device_path_length < path.length() &&
+ path[platform_device_path_length] == '/' &&
+ android::base::StartsWith(path, it->c_str())) {
+ *out_path = *it;
+ return true;
}
}
-}
-
-static void destroy_platform_devices() {
- struct listnode* node;
- struct listnode* n;
- struct platform_node* bus;
-
- 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);
- }
+ return false;
}
/* Given a path that may start with a PCI device, populate the supplied buffer
@@ -442,16 +385,13 @@
}
std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
- platform_node* pdev = find_platform_device(uevent->path.c_str());
- if (!pdev) return {};
+ std::string parent_device;
+ if (!find_platform_device(uevent->path, &parent_device)) return {};
- /* skip "/devices/platform/<driver>" */
- auto parent_start = uevent->path.find('/', pdev->path_len);
- if (parent_start == std::string::npos) return {};
+ // skip path to the parent driver
+ std::string path = uevent->path.substr(parent_device.length());
- std::string parent = uevent->path.substr(parent_start);
-
- if (!android::base::StartsWith(parent, "/usb")) return {};
+ if (!android::base::StartsWith(path, "/usb")) return {};
// skip root hub name and device. use device interface
// skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
@@ -459,13 +399,13 @@
// e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
std::string::size_type start = 0;
- start = parent.find('/', start + 1);
+ start = path.find('/', start + 1);
if (start == std::string::npos) return {};
- start = parent.find('/', start + 1);
+ start = path.find('/', start + 1);
if (start == std::string::npos) return {};
- auto end = parent.find('/', start + 1);
+ auto end = path.find('/', start + 1);
if (end == std::string::npos) return {};
start++; // Skip the first '/'
@@ -473,7 +413,7 @@
auto length = end - start;
if (length == 0) return {};
- auto name_string = parent.substr(start, length);
+ auto name_string = path.substr(start, length);
std::vector<std::string> links;
links.emplace_back("/dev/usb/" + uevent->subsystem + name_string);
@@ -502,12 +442,19 @@
std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
std::string device;
- struct platform_node* pdev;
std::string type;
- pdev = find_platform_device(uevent->path.c_str());
- if (pdev) {
- device = pdev->name;
+ if (find_platform_device(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, &device)) {
type = "pci";
@@ -575,11 +522,12 @@
}
}
-static void handle_platform_device_event(uevent* uevent) {
+void handle_platform_device_event(uevent* uevent) {
if (uevent->action == "add") {
- add_platform_device(uevent->path.c_str());
+ platform_devices.emplace_back(uevent->path);
} else if (uevent->action == "remove") {
- remove_platform_device(uevent->path.c_str());
+ auto it = std::find(platform_devices.begin(), platform_devices.end(), uevent->path);
+ if (it != platform_devices.end()) platform_devices.erase(it);
}
}
@@ -920,7 +868,7 @@
}
void device_close() {
- destroy_platform_devices();
+ platform_devices.clear();
device_fd.reset();
selinux_status_close();
}
diff --git a/init/devices.h b/init/devices.h
index c12ba9d..b8b039f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -59,10 +59,11 @@
int get_device_fd();
// Exposed for testing
-void add_platform_device(const char* path);
-void remove_platform_device(const char* path);
+extern std::vector<std::string> platform_devices;
+bool find_platform_device(const std::string& path, std::string* out_path);
std::vector<std::string> get_character_device_symlinks(uevent* uevent);
std::vector<std::string> get_block_device_symlinks(uevent* uevent);
void sanitize_partition_name(std::string* string);
+void handle_platform_device_event(uevent* uevent);
#endif /* _INIT_DEVICES_H */
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index b6b4b82..693fb54 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -22,12 +22,26 @@
#include <android-base/scopeguard.h>
#include <gtest/gtest.h>
+void add_platform_device(const std::string& path) {
+ uevent uevent = {
+ .action = "add", .subsystem = "platform", .path = path,
+ };
+ handle_platform_device_event(&uevent);
+}
+
+void remove_platform_device(const std::string& path) {
+ uevent uevent = {
+ .action = "remove", .subsystem = "platform", .path = path,
+ };
+ handle_platform_device_event(&uevent);
+}
+
template <std::vector<std::string> (*Function)(uevent*)>
void test_get_symlinks(const std::string& platform_device_name, uevent* uevent,
const std::vector<std::string> expected_links) {
- add_platform_device(platform_device_name.c_str());
+ add_platform_device(platform_device_name);
auto platform_device_remover = android::base::make_scope_guard(
- [&platform_device_name]() { remove_platform_device(platform_device_name.c_str()); });
+ [&platform_device_name]() { remove_platform_device(platform_device_name); });
std::vector<std::string> result = Function(uevent);
@@ -41,6 +55,36 @@
}
}
+TEST(devices, handle_platform_device_event) {
+ platform_devices.clear();
+ add_platform_device("/devices/platform/some_device_name");
+ ASSERT_EQ(1U, platform_devices.size());
+ remove_platform_device("/devices/platform/some_device_name");
+ ASSERT_EQ(0U, platform_devices.size());
+}
+
+TEST(devices, find_platform_device) {
+ platform_devices.clear();
+ add_platform_device("/devices/platform/some_device_name");
+ add_platform_device("/devices/platform/some_device_name/longer");
+ add_platform_device("/devices/platform/other_device_name");
+ EXPECT_EQ(3U, platform_devices.size());
+
+ std::string out_path;
+ EXPECT_FALSE(find_platform_device("/devices/platform/not_found", &out_path));
+ EXPECT_EQ("", out_path);
+
+ EXPECT_FALSE(
+ find_platform_device("/devices/platform/some_device_name_with_same_prefix", &out_path));
+
+ EXPECT_TRUE(
+ find_platform_device("/devices/platform/some_device_name/longer/longer_child", &out_path));
+ EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
+
+ EXPECT_TRUE(find_platform_device("/devices/platform/some_device_name/other_child", &out_path));
+ EXPECT_EQ("/devices/platform/some_device_name", out_path);
+}
+
TEST(devices, get_character_device_symlinks_success) {
const char* platform_device = "/devices/platform/some_device_name";
uevent uevent = {