power: Add a Udev wrapper around udev_device_get_devlinks_list_entry

Proximity sensors are given devlinks that correspond to what kind of device
they are a source of proximity info for (e.g. proximity-lte,
proximity-wifi-left).

This helper function allows powerd to discover the devlinks that udev has
assigned to a given device.

TEST=manual
BUG=b:74586744

Change-Id: Ie99b209d7cc40d928d0ca013f1aa3c4b9a540211
Signed-off-by: Enrico Granata <egranata@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1148957
Reviewed-by: Dan Erat <derat@chromium.org>
(cherry picked from commit 73786143269064238e159c2804a767a4a8415cdf)
Reviewed-on: https://chromium-review.googlesource.com/1154709
Commit-Queue: Jongpil Jung <jongpil19.jung@samsung.corp-partner.google.com>
Tested-by: Jongpil Jung <jongpil19.jung@samsung.corp-partner.google.com>
diff --git a/power_manager/powerd/system/input_watcher_unittest.cc b/power_manager/powerd/system/input_watcher_unittest.cc
index a86d542..27e730d 100644
--- a/power_manager/powerd/system/input_watcher_unittest.cc
+++ b/power_manager/powerd/system/input_watcher_unittest.cc
@@ -171,7 +171,7 @@
     input_device_info.sysname = name;
     input_device_info.syspath = syspath;
     udev_.AddSubsystemDevice(InputWatcher::kInputUdevSubsystem,
-                             input_device_info);
+                             input_device_info, {});
     event_device_factory_->RegisterDevice(path, device);
   }
 
diff --git a/power_manager/powerd/system/udev.cc b/power_manager/powerd/system/udev.cc
index 080a362..50b9fea 100644
--- a/power_manager/powerd/system/udev.cc
+++ b/power_manager/powerd/system/udev.cc
@@ -15,6 +15,7 @@
 #include "power_manager/powerd/system/tagged_device.h"
 #include "power_manager/powerd/system/udev_subsystem_observer.h"
 #include "power_manager/powerd/system/udev_tagged_device_observer.h"
+#include "power_manager/powerd/system/udev_util.h"
 
 namespace power_manager {
 namespace system {
@@ -65,6 +66,13 @@
   return true;
 }
 
+struct UdevDeviceDeleter {
+  void operator()(udev_device* dev) {
+    if (dev)
+      udev_device_unref(dev);
+  }
+};
+
 };  // namespace
 
 Udev::Udev() : udev_(NULL), udev_monitor_(NULL) {}
@@ -274,6 +282,34 @@
   return parent != NULL;
 }
 
+bool Udev::GetDevlinks(const std::string& syspath,
+                       std::vector<std::string>* out) {
+  DCHECK(udev_);
+  DCHECK(out);
+
+  std::unique_ptr<udev_device, UdevDeviceDeleter> device(
+      udev_device_new_from_syspath(udev_, syspath.c_str()));
+  if (!device) {
+    PLOG(WARNING) << "Failed to open udev device: " << syspath;
+    return false;
+  }
+
+  out->clear();
+
+  // TODO(egranata): maybe write a wrapper around udev_list to support
+  // for(entry : list) {...}
+  struct udev_list_entry* devlink =
+      udev_device_get_devlinks_list_entry(device.get());
+  while (devlink) {
+    const char* name = udev_list_entry_get_name(devlink);
+    if (name)
+      out->push_back(name);
+    devlink = udev_list_entry_get_next(devlink);
+  }
+
+  return true;
+}
+
 void Udev::OnFileCanReadWithoutBlocking(int fd) {
   struct udev_device* dev = udev_monitor_receive_device(udev_monitor_);
   if (!dev)
diff --git a/power_manager/powerd/system/udev.h b/power_manager/powerd/system/udev.h
index 6564285..748a3d4 100644
--- a/power_manager/powerd/system/udev.h
+++ b/power_manager/powerd/system/udev.h
@@ -96,6 +96,11 @@
                                      const std::string& sysattr,
                                      const std::string& stop_at_devtype,
                                      std::string* parent_syspath) = 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.
@@ -127,6 +132,8 @@
                              const std::string& sysattr,
                              const std::string& stopat_devtype,
                              std::string* parent_syspath) override;
+  bool GetDevlinks(const std::string& syspath,
+                   std::vector<std::string>* out) override;
 
   // base::MessageLoopForIO::Watcher implementation:
   void OnFileCanReadWithoutBlocking(int fd) override;
diff --git a/power_manager/powerd/system/udev_stub.cc b/power_manager/powerd/system/udev_stub.cc
index 9a93cc8..6db54c0 100644
--- a/power_manager/powerd/system/udev_stub.cc
+++ b/power_manager/powerd/system/udev_stub.cc
@@ -50,8 +50,10 @@
 }
 
 void UdevStub::AddSubsystemDevice(const std::string& subsystem,
-                                  const UdevDeviceInfo& udev_device) {
+                                  const UdevDeviceInfo& udev_device,
+                                  std::initializer_list<std::string> dlinks) {
   subsystem_devices_[subsystem].push_back(udev_device);
+  devlinks_.emplace(udev_device.syspath, dlinks);
 }
 
 void UdevStub::AddSubsystemObserver(const std::string& subsystem,
@@ -131,5 +133,15 @@
   return true;
 }
 
+bool UdevStub::GetDevlinks(const std::string& syspath,
+                           std::vector<std::string>* out) {
+  auto iter = devlinks_.find(syspath);
+  if (iter == devlinks_.end())
+    return false;
+
+  *out = iter->second;
+  return true;
+}
+
 }  // namespace system
 }  // namespace power_manager
diff --git a/power_manager/powerd/system/udev_stub.h b/power_manager/powerd/system/udev_stub.h
index 16a909a..8f56b53 100644
--- a/power_manager/powerd/system/udev_stub.h
+++ b/power_manager/powerd/system/udev_stub.h
@@ -43,7 +43,8 @@
 
   // Adds a device to be returned by GetSubsystemDevices.
   void AddSubsystemDevice(const std::string& subsystem,
-                          const UdevDeviceInfo& udev_device);
+                          const UdevDeviceInfo& udev_device,
+                          std::initializer_list<std::string> devlinks);
 
   // UdevInterface implementation:
   void AddSubsystemObserver(const std::string& subsystem,
@@ -65,6 +66,8 @@
                              const std::string& sysattr,
                              const std::string& stop_at_devtype,
                              std::string* parent_syspath) override;
+  bool GetDevlinks(const std::string& syspath,
+                   std::vector<std::string>* out) override;
 
  private:
   // List of subsystem devices returned when GetSubsystemDevices is called.
@@ -82,6 +85,9 @@
   // Maps a syspath to the corresponding TaggedDevice.
   std::map<std::string, TaggedDevice> tagged_devices_;
 
+  // Maps a syspath to the corresponding devlinks.
+  std::map<std::string, std::vector<std::string>> devlinks_;
+
   // Maps a pair (device syspath, sysattr name) to the corresponding sysattr
   // value.
   typedef std::map<std::pair<std::string, std::string>, std::string> SysattrMap;