Merge "Revert "ueventd: remove PlatformDeviceList"" into oc-dev

This commit is contained in:
Tom Cherry 2017-06-21 18:18:23 +00:00 committed by Android (Google) Code Review
commit fef83abd89
2 changed files with 105 additions and 45 deletions

View file

@ -46,7 +46,6 @@
#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>
@ -80,8 +79,16 @@ struct perm_node {
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,
@ -279,37 +286,77 @@ out:
}
}
// 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();
static void add_platform_device(const char *path)
{
int path_len = strlen(path);
struct platform_node *bus;
const char *name = path;
static const std::string kSysfsMountPoint = "/sys";
// Uevents don't contain the mount point, so we need to add it here.
path.insert(0, kSysfsMountPoint);
std::string directory = android::base::Dirname(path);
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;
}
auto last_slash = path.rfind('/');
if (last_slash == std::string::npos) return false;
path.erase(last_slash);
directory = android::base::Dirname(path);
if (!strncmp(path, "/devices/", 9)) {
name += 9;
if (!strncmp(name, "platform/", 9))
name += 9;
}
return false;
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;
}
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;
}
}
}
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);
}
}
/* Given a path that may start with a PCI device, populate the supplied buffer
@ -433,9 +480,11 @@ static char **get_character_device_symlinks(struct uevent *uevent)
char **links;
int link_num = 0;
int width;
struct platform_node *pdev;
std::string platform_device;
if (!FindPlatformDevice(uevent->path, &platform_device)) return nullptr;
pdev = find_platform_device(uevent->path);
if (!pdev)
return NULL;
links = (char**) malloc(sizeof(char *) * 2);
if (!links)
@ -443,7 +492,7 @@ static char **get_character_device_symlinks(struct uevent *uevent)
memset(links, 0, sizeof(char *) * 2);
/* skip "/devices/platform/<driver>" */
parent = strchr(uevent->path + platform_device.size(), '/');
parent = strchr(uevent->path + pdev->path_len, '/');
if (!parent)
goto err;
@ -478,6 +527,8 @@ err:
}
char** get_block_device_symlinks(struct uevent* uevent) {
const char *device;
struct platform_node *pdev;
const char *slash;
const char *type;
char buf[256];
@ -485,18 +536,9 @@ char** get_block_device_symlinks(struct uevent* uevent) {
int link_num = 0;
char *p;
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());
}
pdev = find_platform_device(uevent->path);
if (pdev) {
device = pdev->name;
type = "platform";
} else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
device = buf;
@ -515,7 +557,7 @@ char** get_block_device_symlinks(struct uevent* uevent) {
LOG(VERBOSE) << "found " << type << " device " << device;
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device.c_str());
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
@ -593,6 +635,16 @@ static void handle_device(const char *action, const char *devpath,
}
}
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;
@ -772,6 +824,8 @@ static void handle_device_event(struct uevent *uevent)
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);
}
@ -1024,6 +1078,7 @@ void device_init(const char* path, coldboot_callback fn) {
}
void device_close() {
destroy_platform_devices();
device_fd.reset();
selinux_status_close();
}

View file

@ -178,6 +178,11 @@ void FirstStageMount::InitRequiredDevices() {
}
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;