Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d17d5c58 authored by Eric Caruso's avatar Eric Caruso
Browse files

ueventd: add support for driver section in ueventd.rc

Allow ueventd configuration to specify what to do with
devices based on driver. This responds to bind events and
treats them similarly to add events.

The format of the driver stanza is exactly the same as
that of the subsystem stanza.

Bug: 376900376
Test: set up cbc_mbim driver stanza and ensure it properly
  creates and destroys device nodes when a USB device with
  that driver appears and disappears or is bound and unbound

Change-Id: I31f5c91bd074d14075b74fe7beefaa6ac07a7ac9
parent d68632be
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -76,17 +76,17 @@ For example
When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to
`root`.

The path can be modified using a ueventd.rc script and a `subsystem` section. There are three to set
for a subsystem: the subsystem name, which device name to use, and which directory to place the
device in. The section takes the below format of
The path can be modified using a ueventd.rc script and a `subsystem` and/or `driver` section.
There are three options to set for a subsystem or driver: the name, which device name to use,
and which directory to place the device in. The section takes the below format of

    subsystem <subsystem_name>
      devname uevent_devname|uevent_devpath
      [dirname <directory>]

`subsystem_name` is used to match uevent `SUBSYSTEM` value
`subsystem_name` is used to match the uevent `SUBSYSTEM` value.

`devname` takes one of three options
`devname` takes one of three options:
  1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME`
  2. `uevent_devpath` specifies that the name of the node will be basename uevent `DEVPATH`
  3. `sys_name` specifies that the name of the node will be the contents of `/sys/DEVPATH/name`
@@ -99,9 +99,13 @@ For example
    subsystem sound
      devname uevent_devpath
      dirname /dev/snd
Indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent
indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent
DEVPATH>`.

The `driver` section has the exact same structure as a `subsystem` section, but
will instead match the `DRIVER` value in a `bind`/`unbind` uevent. However, the
`driver` section will be ignored for block devices.

## /sys
----
Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for
+2 −1
Original line number Diff line number Diff line
@@ -33,7 +33,8 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024)
    auto boot_devices = android::fs_mgr::GetBootDevices();
    device_handler_ = std::make_unique<DeviceHandler>(
            std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
            std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false);
            std::vector<Subsystem>{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(),
            false);
}

// If boot_part_uuid is specified, use it to set boot_devices
+69 −3
Original line number Diff line number Diff line
@@ -345,6 +345,26 @@ bool DeviceHandler::FindScsiDevice(const std::string& path, std::string* scsi_de
    return FindSubsystemDevice(path, scsi_device_path, subsystem_paths);
}

void DeviceHandler::TrackDeviceUevent(const Uevent& uevent) {
    // No need to track any events if we won't bother handling any bind events
    // later.
    if (drivers_.size() == 0) return;

    // Only track add, and not for block devices. We don't track remove because
    // unbind events may arrive after remove events, so unbind will be the
    // trigger to untrack those events.
    if ((uevent.action != "add") || uevent.subsystem == "block" ||
        (uevent.major < 0 || uevent.minor < 0)) {
        return;
    }

    std::string path = sysfs_mount_point_ + uevent.path + "/device";
    std::string device;
    if (!Realpath(path, &device)) return;

    tracked_uevents_.emplace_back(uevent, device);
}

void DeviceHandler::FixupSysPermissions(const std::string& upath,
                                        const std::string& subsystem) const {
    // upaths omit the "/sys" that paths in this list
@@ -664,12 +684,53 @@ bool DeviceHandler::CheckUeventForBootPartUuid(const Uevent& uevent) {
    return true;
}

void DeviceHandler::HandleBindInternal(std::string driver_name, std::string action,
                                       const Uevent& uevent) {
    if (uevent.subsystem == "block") {
        LOG(FATAL) << "Tried to handle bind event for block device";
    }

    // Get tracked uevents for all devices that have this uevent's path as
    // their canonical device path. Then handle those again if their driver
    // is one of the ones we're interested in.
    const auto driver = std::find(drivers_.cbegin(), drivers_.cend(), driver_name);
    if (driver == drivers_.cend()) return;

    std::string bind_path = sysfs_mount_point_ + uevent.path;
    for (const TrackedUevent& tracked : tracked_uevents_) {
        if (tracked.canonical_device_path != bind_path) continue;

        LOG(VERBOSE) << "Propagating " << uevent.action << " as " << action << " for "
                     << uevent.path;

        std::string devpath = driver->ParseDevPath(tracked.uevent);
        mkdir_recursive(Dirname(devpath), 0755);
        HandleDevice(action, devpath, false, tracked.uevent.major, tracked.uevent.minor,
                     std::vector<std::string>{});
    }
}

void DeviceHandler::HandleUevent(const Uevent& uevent) {
    if (uevent.action == "add" || uevent.action == "change" || uevent.action == "bind" ||
        uevent.action == "online") {
        FixupSysPermissions(uevent.path, uevent.subsystem);
    }

    if (uevent.action == "bind") {
        bound_drivers_[uevent.path] = uevent.driver;
        HandleBindInternal(uevent.driver, "add", uevent);
        return;
    } else if (uevent.action == "unbind") {
        if (bound_drivers_.count(uevent.path) == 0) return;
        HandleBindInternal(bound_drivers_[uevent.path], "remove", uevent);

        std::string sys_path = sysfs_mount_point_ + uevent.path;
        std::erase_if(tracked_uevents_, [&sys_path](const TrackedUevent& tracked) {
            return sys_path == tracked.canonical_device_path;
        });
        return;
    }

    // if it's not a /dev device, nothing to do
    if (uevent.major < 0 || uevent.minor < 0) return;

@@ -677,6 +738,8 @@ void DeviceHandler::HandleUevent(const Uevent& uevent) {
    std::vector<std::string> links;
    bool block = false;

    TrackDeviceUevent(uevent);

    if (uevent.subsystem == "block") {
        block = true;
        devpath = "/dev/block/" + Basename(uevent.path);
@@ -725,10 +788,12 @@ void DeviceHandler::ColdbootDone() {

DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
                             std::vector<SysfsPermissions> sysfs_permissions,
                             std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
                             std::string boot_part_uuid, bool skip_restorecon)
                             std::vector<Subsystem> drivers, std::vector<Subsystem> subsystems,
                             std::set<std::string> boot_devices, std::string boot_part_uuid,
                             bool skip_restorecon)
    : dev_permissions_(std::move(dev_permissions)),
      sysfs_permissions_(std::move(sysfs_permissions)),
      drivers_(std::move(drivers)),
      subsystems_(std::move(subsystems)),
      boot_devices_(std::move(boot_devices)),
      boot_part_uuid_(boot_part_uuid),
@@ -744,7 +809,8 @@ DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,

DeviceHandler::DeviceHandler()
    : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
                    std::vector<Subsystem>{}, std::set<std::string>{}, "", false) {}
                    std::vector<Subsystem>{}, std::vector<Subsystem>{}, std::set<std::string>{}, "",
                    false) {}

}  // namespace init
}  // namespace android
+14 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <sys/types.h>

#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <vector>
@@ -128,7 +129,7 @@ class DeviceHandler : public UeventHandler {

    DeviceHandler();
    DeviceHandler(std::vector<Permissions> dev_permissions,
                  std::vector<SysfsPermissions> sysfs_permissions,
                  std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> drivers,
                  std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
                  std::string boot_part_uuid, bool skip_restorecon);
    virtual ~DeviceHandler() = default;
@@ -145,6 +146,11 @@ class DeviceHandler : public UeventHandler {
    bool IsBootDevice(const Uevent& uevent) const;

  private:
    struct TrackedUevent {
        Uevent uevent;
        std::string canonical_device_path;
    };

    void ColdbootDone() override;
    BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const;
    bool FindSubsystemDevice(std::string path, std::string* device_path,
@@ -163,14 +169,21 @@ class DeviceHandler : public UeventHandler {
    void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
    void HandleAshmemUevent(const Uevent& uevent);

    void TrackDeviceUevent(const Uevent& uevent);
    void HandleBindInternal(std::string driver_name, std::string action, const Uevent& uevent);

    std::vector<Permissions> dev_permissions_;
    std::vector<SysfsPermissions> sysfs_permissions_;
    std::vector<Subsystem> drivers_;
    std::vector<Subsystem> subsystems_;
    std::set<std::string> boot_devices_;
    std::string boot_part_uuid_;
    bool found_boot_part_uuid_;
    bool skip_restorecon_;
    std::string sysfs_mount_point_;

    std::vector<TrackedUevent> tracked_uevents_;
    std::map<std::string, std::string> bound_drivers_;
};

// Exposed for testing
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ struct Uevent {
    std::string action;
    std::string path;
    std::string subsystem;
    std::string driver;
    std::string firmware;
    std::string partition_name;
    std::string partition_uuid;
Loading