blob: 695649e5afa94f95b801e0ec7f47859887079c58 [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef POWER_MANAGER_POWERD_SYSTEM_UDEV_H_
#define POWER_MANAGER_POWERD_SYSTEM_UDEV_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/files/file_path.h>
#include <base/macros.h>
#include <base/observer_list.h>
struct udev;
struct udev_device;
struct udev_monitor;
namespace power_manager {
namespace system {
class TaggedDevice;
class UdevSubsystemObserver;
class UdevTaggedDeviceObserver;
struct UdevDeviceInfo {
std::string subsystem;
std::string devtype;
std::string sysname;
std::string syspath;
// Directory (of itself/ancestor) with power/wakeup property.
base::FilePath wakeup_device_path;
};
// UdevEvent describes a udev event.
struct UdevEvent {
enum class Action {
ADD = 0,
REMOVE,
CHANGE,
ONLINE,
OFFLINE,
UNKNOWN,
};
UdevDeviceInfo device_info;
Action action;
};
// Watches the udev manager for device-related events (e.g. hotplug).
class UdevInterface {
public:
UdevInterface() {}
virtual ~UdevInterface() {}
// Adds or removes an observer for watching |subsystem|. To receive events,
// this subsystem must also be given a "powerd" tag by
// udev/94-powerd-late.rules.
virtual void AddSubsystemObserver(const std::string& subsystem,
UdevSubsystemObserver* observer) = 0;
virtual void RemoveSubsystemObserver(const std::string& subsystem,
UdevSubsystemObserver* observer) = 0;
// Adds/removes an observer that will receive events for tagged devices.
virtual void AddTaggedDeviceObserver(UdevTaggedDeviceObserver* observer) = 0;
virtual void RemoveTaggedDeviceObserver(
UdevTaggedDeviceObserver* observer) = 0;
// Retrieves a list of all known tagged devices.
virtual std::vector<TaggedDevice> GetTaggedDevices() = 0;
// Retrieves the list of existing devices that belong to the given subsystem.
virtual bool GetSubsystemDevices(
const std::string& subsystem,
std::vector<UdevDeviceInfo>* devices_out) = 0;
// Reads the sysfs attribute |sysattr| from the device specified by |syspath|.
// Returns true on success. |syspath| is the syspath of a device as returned
// by libudev, e.g.
// "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/input/input22".
virtual bool GetSysattr(const std::string& syspath,
const std::string& sysattr,
std::string* value) = 0;
// Sets the value of a sysfs attribute. Returns true on success.
virtual bool SetSysattr(const std::string& syspath,
const std::string& sysattr,
const std::string& value) = 0;
// For the device specified by |syspath|, finds all the devlinks that
// udev configured, and stores their paths in |out|.
virtual bool GetDevlinks(const std::string& syspath,
std::vector<std::string>* out) = 0;
};
// Actual implementation of UdevInterface.
class Udev : public UdevInterface {
public:
Udev();
Udev(const Udev&) = delete;
Udev& operator=(const Udev&) = delete;
~Udev() override;
// Initializes the object to listen for events. Returns true on success.
bool Init();
// UdevInterface implementation:
void AddSubsystemObserver(const std::string& subsystem,
UdevSubsystemObserver* observer) override;
void RemoveSubsystemObserver(const std::string& subsystem,
UdevSubsystemObserver* observer) override;
void AddTaggedDeviceObserver(UdevTaggedDeviceObserver* observer) override;
void RemoveTaggedDeviceObserver(UdevTaggedDeviceObserver* observer) override;
std::vector<TaggedDevice> GetTaggedDevices() override;
bool GetSubsystemDevices(const std::string& subsystem,
std::vector<UdevDeviceInfo>* devices_out) override;
bool GetSysattr(const std::string& syspath,
const std::string& sysattr,
std::string* value) override;
bool SetSysattr(const std::string& syspath,
const std::string& sysattr,
const std::string& value) override;
bool GetDevlinks(const std::string& syspath,
std::vector<std::string>* out) override;
void OnFileCanReadWithoutBlocking();
private:
void HandleSubsystemEvent(UdevEvent::Action action, struct udev_device* dev);
void HandleTaggedDevice(UdevEvent::Action action, struct udev_device* dev);
void TaggedDeviceChanged(const std::string& syspath,
const base::FilePath& wakeup_device_path,
const std::string& tags);
void TaggedDeviceRemoved(const std::string& syspath);
// Populates |tagged_devices_| with currently-existing devices.
bool EnumerateTaggedDevices();
// For the udev_device specified by |syspath|, finds the first parent device
// which has a sysattr named |sysattr|, and returns the parent's syspath.
// If |stop_at_devtype| is a nonempty string, then no parent devices will be
// considered beyond the first device matching |stop_at_devtype|. Returns
// syspath of the parent with the |sysattr| on success, or an empty path
// when no matching parent device was found.
base::FilePath FindParentWithSysattr(const std::string& syspath,
const std::string& sysattr,
const std::string& stop_at_devtype);
// Returns the first ancestor which is wake capable (i.e has power/wakeup
// property). If the passed device with sysfs path |syspath| is wake capable,
// returns the same.
// For input devices controlled by 'crosec' which are not wake capable
// by themselves, this function is expected to travel the hierarchy to find
// crosec which is wake capable.
// For USB devices, the input device does not have a power/wakeup property
// itself, but the corresponding USB device does. If the matching device does
// not have a power/wakeup property, we thus fall back to the first ancestor
// that has one. Conflicts should not arise, since real-world USB input
// devices typically only expose one input interface anyway. However, crawling
// up sysfs should only reach the first "usb_device" node, because
// higher-level nodes include USB hubs, and enabling wakeups on those isn't a
// good idea.
base::FilePath FindWakeCapableParent(const std::string& syspath);
bool GetDeviceInfo(struct udev_device* dev, UdevDeviceInfo* device_info_out);
struct udev* udev_;
struct udev_monitor* udev_monitor_;
// Maps from a subsystem name to the corresponding observers.
std::map<std::string,
std::unique_ptr<base::ObserverList<UdevSubsystemObserver>>>
subsystem_observers_;
base::ObserverList<UdevTaggedDeviceObserver> tagged_device_observers_;
// Maps a syspath to the corresponding TaggedDevice.
std::map<std::string, TaggedDevice> tagged_devices_;
// Controller for watching |udev_monitor_|'s FD for readability.
std::unique_ptr<base::FileDescriptorWatcher::Controller> controller_;
};
} // namespace system
} // namespace power_manager
#endif // POWER_MANAGER_POWERD_SYSTEM_UDEV_H_