Update Smart lock strings in chrome://settings.
[chromium-blink-merge.git] / device / hid / hid_service_linux.cc
blob45688f5b8b7f6a35a34d49277d67a49c3c4d1992
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/hid/hid_service_linux.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/files/file.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/string_split.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "device/hid/hid_connection_linux.h"
21 #include "device/hid/hid_device_info.h"
22 #include "device/hid/hid_report_descriptor.h"
23 #include "device/udev_linux/scoped_udev.h"
25 #if defined(OS_CHROMEOS)
26 #include "base/sys_info.h"
27 #include "chromeos/dbus/dbus_thread_manager.h"
28 #include "chromeos/dbus/permission_broker_client.h"
29 #endif // defined(OS_CHROMEOS)
31 namespace device {
33 namespace {
35 const char kHidrawSubsystem[] = "hidraw";
36 const char kHIDID[] = "HID_ID";
37 const char kHIDName[] = "HID_NAME";
38 const char kHIDUnique[] = "HID_UNIQ";
39 const char kSysfsReportDescriptorKey[] = "report_descriptor";
41 #if defined(OS_CHROMEOS)
42 void OnRequestAccessComplete(
43 scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
44 const base::Callback<void(bool success)>& callback,
45 bool success) {
46 reply_task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
49 void RequestAccess(
50 const std::string& device_node,
51 scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
52 const base::Callback<void(bool success)>& callback) {
53 bool success = false;
55 if (base::SysInfo::IsRunningOnChromeOS()) {
56 chromeos::PermissionBrokerClient* client =
57 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
58 DCHECK(client) << "Could not get permission broker client.";
59 if (client) {
60 client->RequestPathAccess(
61 device_node,
62 -1,
63 base::Bind(OnRequestAccessComplete, reply_task_runner, callback));
64 return;
66 } else {
67 // Not really running on Chrome OS, declare success.
68 success = true;
71 reply_task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
73 #endif
75 } // namespace
77 HidServiceLinux::HidServiceLinux(
78 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
79 : ui_task_runner_(ui_task_runner),
80 weak_factory_(this) {
81 base::ThreadRestrictions::AssertIOAllowed();
82 task_runner_ = base::ThreadTaskRunnerHandle::Get();
83 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
84 monitor->AddObserver(this);
85 monitor->Enumerate(
86 base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr()));
89 void HidServiceLinux::Connect(const HidDeviceId& device_id,
90 const ConnectCallback& callback) {
91 DCHECK(thread_checker_.CalledOnValidThread());
93 ScopedUdevDevicePtr device =
94 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
95 device_id);
96 if (!device) {
97 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
98 return;
101 const char* device_node = udev_device_get_devnode(device.get());
102 if (!device_node) {
103 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
104 return;
107 base::Callback<void(bool success)> finish_connect =
108 base::Bind(&HidServiceLinux::FinishConnect,
109 weak_factory_.GetWeakPtr(),
110 device_id,
111 std::string(device_node),
112 callback);
114 #if defined(OS_CHROMEOS)
115 ui_task_runner_->PostTask(FROM_HERE,
116 base::Bind(RequestAccess,
117 std::string(device_node),
118 task_runner_,
119 finish_connect));
120 #else
121 // Use the task runner to preserve the asynchronous behavior of this call on
122 // non-Chrome OS platforms.
123 task_runner_->PostTask(FROM_HERE, base::Bind(finish_connect, true));
124 #endif
127 HidServiceLinux::~HidServiceLinux() {
128 if (DeviceMonitorLinux::HasInstance())
129 DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
132 void HidServiceLinux::OnDeviceAdded(udev_device* device) {
133 if (!device)
134 return;
136 const char* device_path = udev_device_get_syspath(device);
137 if (!device_path)
138 return;
139 const char* subsystem = udev_device_get_subsystem(device);
140 if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0)
141 return;
143 HidDeviceInfo device_info;
144 device_info.device_id = device_path;
146 uint32_t int_property = 0;
147 const char* str_property = NULL;
149 udev_device* parent = udev_device_get_parent(device);
150 if (!parent) {
151 return;
154 const char* hid_id = udev_device_get_property_value(parent, kHIDID);
155 if (!hid_id) {
156 return;
159 std::vector<std::string> parts;
160 base::SplitString(hid_id, ':', &parts);
161 if (parts.size() != 3) {
162 return;
165 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) {
166 device_info.vendor_id = int_property;
169 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) {
170 device_info.product_id = int_property;
173 str_property = udev_device_get_property_value(parent, kHIDUnique);
174 if (str_property != NULL) {
175 device_info.serial_number = str_property;
178 str_property = udev_device_get_property_value(parent, kHIDName);
179 if (str_property != NULL) {
180 device_info.product_name = str_property;
183 const char* parent_sysfs_path = udev_device_get_syspath(parent);
184 if (!parent_sysfs_path) {
185 return;
187 base::FilePath report_descriptor_path =
188 base::FilePath(parent_sysfs_path).Append(kSysfsReportDescriptorKey);
189 std::string report_descriptor_str;
190 if (!base::ReadFileToString(report_descriptor_path, &report_descriptor_str)) {
191 return;
194 HidReportDescriptor report_descriptor(
195 reinterpret_cast<uint8_t*>(&report_descriptor_str[0]),
196 report_descriptor_str.length());
197 report_descriptor.GetDetails(&device_info.collections,
198 &device_info.has_report_id,
199 &device_info.max_input_report_size,
200 &device_info.max_output_report_size,
201 &device_info.max_feature_report_size);
203 AddDevice(device_info);
206 void HidServiceLinux::OnDeviceRemoved(udev_device* device) {
207 const char* device_path = udev_device_get_syspath(device);;
208 if (device_path) {
209 RemoveDevice(device_path);
213 void HidServiceLinux::FinishConnect(
214 const HidDeviceId& device_id,
215 const std::string device_node,
216 const base::Callback<void(scoped_refptr<HidConnection>)>& callback,
217 bool success) {
218 DCHECK(thread_checker_.CalledOnValidThread());
219 if (!success) {
220 callback.Run(nullptr);
223 const auto& map_entry = devices().find(device_id);
224 if (map_entry == devices().end()) {
225 callback.Run(nullptr);
228 callback.Run(new HidConnectionLinux(map_entry->second, device_node));
231 } // namespace device