| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/hid/hid_service_linux.h" | 5 #include "device/hid/hid_service_linux.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <limits> | 10 #include <limits> |
| 11 #include <memory> | 11 #include <memory> |
| 12 #include <string> | 12 #include <string> |
| 13 #include <utility> | 13 #include <utility> |
| 14 | 14 |
| 15 #include "base/bind.h" | 15 #include "base/bind.h" |
| 16 #include "base/files/file.h" | 16 #include "base/files/file.h" |
| 17 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
| 18 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
| 19 #include "base/files/scoped_file.h" |
| 19 #include "base/location.h" | 20 #include "base/location.h" |
| 20 #include "base/macros.h" | 21 #include "base/macros.h" |
| 21 #include "base/memory/ptr_util.h" | 22 #include "base/memory/ptr_util.h" |
| 22 #include "base/scoped_observer.h" | 23 #include "base/scoped_observer.h" |
| 23 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" |
| 24 #include "base/strings/string_split.h" | 25 #include "base/strings/string_split.h" |
| 25 #include "base/threading/thread_restrictions.h" | 26 #include "base/threading/thread_restrictions.h" |
| 26 #include "base/threading/thread_task_runner_handle.h" | 27 #include "base/threading/thread_task_runner_handle.h" |
| 27 #include "build/build_config.h" | 28 #include "build/build_config.h" |
| 28 #include "components/device_event_log/device_event_log.h" | 29 #include "components/device_event_log/device_event_log.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 45 const char kHIDID[] = "HID_ID"; | 46 const char kHIDID[] = "HID_ID"; |
| 46 const char kHIDName[] = "HID_NAME"; | 47 const char kHIDName[] = "HID_NAME"; |
| 47 const char kHIDUnique[] = "HID_UNIQ"; | 48 const char kHIDUnique[] = "HID_UNIQ"; |
| 48 const char kSysfsReportDescriptorKey[] = "report_descriptor"; | 49 const char kSysfsReportDescriptorKey[] = "report_descriptor"; |
| 49 | 50 |
| 50 } // namespace | 51 } // namespace |
| 51 | 52 |
| 52 struct HidServiceLinux::ConnectParams { | 53 struct HidServiceLinux::ConnectParams { |
| 53 ConnectParams(scoped_refptr<HidDeviceInfoLinux> device_info, | 54 ConnectParams(scoped_refptr<HidDeviceInfoLinux> device_info, |
| 54 const ConnectCallback& callback, | 55 const ConnectCallback& callback, |
| 55 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 56 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 56 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) | 57 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
| 57 : device_info(device_info), | 58 : device_info(std::move(device_info)), |
| 58 callback(callback), | 59 callback(callback), |
| 59 task_runner(task_runner), | 60 task_runner(std::move(task_runner)), |
| 60 file_task_runner(file_task_runner) {} | 61 blocking_task_runner(std::move(blocking_task_runner)) {} |
| 61 ~ConnectParams() {} | 62 ~ConnectParams() {} |
| 62 | 63 |
| 63 scoped_refptr<HidDeviceInfoLinux> device_info; | 64 scoped_refptr<HidDeviceInfoLinux> device_info; |
| 64 ConnectCallback callback; | 65 ConnectCallback callback; |
| 65 scoped_refptr<base::SingleThreadTaskRunner> task_runner; | 66 scoped_refptr<base::SequencedTaskRunner> task_runner; |
| 66 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner; | 67 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner; |
| 67 base::File device_file; | 68 base::ScopedFD fd; |
| 68 }; | 69 }; |
| 69 | 70 |
| 70 class HidServiceLinux::FileThreadHelper : public DeviceMonitorLinux::Observer { | 71 class HidServiceLinux::FileThreadHelper : public DeviceMonitorLinux::Observer { |
| 71 public: | 72 public: |
| 72 FileThreadHelper(base::WeakPtr<HidServiceLinux> service, | 73 FileThreadHelper(base::WeakPtr<HidServiceLinux> service, |
| 73 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 74 scoped_refptr<base::SequencedTaskRunner> task_runner) |
| 74 : observer_(this), service_(service), task_runner_(task_runner) { | 75 : observer_(this), service_(service), task_runner_(task_runner) { |
| 75 thread_checker_.DetachFromThread(); | 76 thread_checker_.DetachFromThread(); |
| 76 } | 77 } |
| 77 | 78 |
| 78 ~FileThreadHelper() override { | 79 ~FileThreadHelper() override { |
| 79 DCHECK(thread_checker_.CalledOnValidThread()); | 80 DCHECK(thread_checker_.CalledOnValidThread()); |
| 80 } | 81 } |
| 81 | 82 |
| 82 void Start() { | 83 void Start() { |
| 83 base::ThreadRestrictions::AssertIOAllowed(); | 84 base::ThreadRestrictions::AssertIOAllowed(); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 FROM_HERE, base::Bind(&HidServiceLinux::RemoveDevice, service_, | 186 FROM_HERE, base::Bind(&HidServiceLinux::RemoveDevice, service_, |
| 186 std::string(device_path))); | 187 std::string(device_path))); |
| 187 } | 188 } |
| 188 } | 189 } |
| 189 | 190 |
| 190 base::ThreadChecker thread_checker_; | 191 base::ThreadChecker thread_checker_; |
| 191 ScopedObserver<DeviceMonitorLinux, DeviceMonitorLinux::Observer> observer_; | 192 ScopedObserver<DeviceMonitorLinux, DeviceMonitorLinux::Observer> observer_; |
| 192 | 193 |
| 193 // This weak pointer is only valid when checked on this task runner. | 194 // This weak pointer is only valid when checked on this task runner. |
| 194 base::WeakPtr<HidServiceLinux> service_; | 195 base::WeakPtr<HidServiceLinux> service_; |
| 195 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 196 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 196 | 197 |
| 197 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper); | 198 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper); |
| 198 }; | 199 }; |
| 199 | 200 |
| 200 HidServiceLinux::HidServiceLinux( | 201 HidServiceLinux::HidServiceLinux( |
| 201 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) | 202 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
| 202 : file_task_runner_(std::move(file_task_runner)), weak_factory_(this) { | 203 : task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 203 task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 204 blocking_task_runner_(std::move(blocking_task_runner)), |
| 205 weak_factory_(this) { |
| 204 helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr(), | 206 helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr(), |
| 205 task_runner_); | 207 task_runner_); |
| 206 file_task_runner_->PostTask( | 208 blocking_task_runner_->PostTask( |
| 207 FROM_HERE, | 209 FROM_HERE, |
| 208 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get()))); | 210 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get()))); |
| 209 } | 211 } |
| 210 | 212 |
| 211 HidServiceLinux::~HidServiceLinux() { | 213 HidServiceLinux::~HidServiceLinux() { |
| 212 DCHECK(!helper_); | 214 DCHECK(!helper_); |
| 213 } | 215 } |
| 214 | 216 |
| 215 void HidServiceLinux::Shutdown() { | 217 void HidServiceLinux::Shutdown() { |
| 216 const bool did_post_task = | 218 const bool did_post_task = |
| 217 file_task_runner_->DeleteSoon(FROM_HERE, helper_.release()); | 219 blocking_task_runner_->DeleteSoon(FROM_HERE, helper_.release()); |
| 218 DCHECK(did_post_task); | 220 DCHECK(did_post_task); |
| 219 HidService::Shutdown(); | 221 HidService::Shutdown(); |
| 220 } | 222 } |
| 221 | 223 |
| 222 void HidServiceLinux::Connect(const HidDeviceId& device_id, | 224 void HidServiceLinux::Connect(const HidDeviceId& device_id, |
| 223 const ConnectCallback& callback) { | 225 const ConnectCallback& callback) { |
| 224 DCHECK(thread_checker_.CalledOnValidThread()); | 226 DCHECK(thread_checker_.CalledOnValidThread()); |
| 225 | 227 |
| 226 const auto& map_entry = devices().find(device_id); | 228 const auto& map_entry = devices().find(device_id); |
| 227 if (map_entry == devices().end()) { | 229 if (map_entry == devices().end()) { |
| 228 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 230 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
| 229 return; | 231 return; |
| 230 } | 232 } |
| 231 scoped_refptr<HidDeviceInfoLinux> device_info = | 233 scoped_refptr<HidDeviceInfoLinux> device_info = |
| 232 static_cast<HidDeviceInfoLinux*>(map_entry->second.get()); | 234 static_cast<HidDeviceInfoLinux*>(map_entry->second.get()); |
| 233 | 235 |
| 234 std::unique_ptr<ConnectParams> params(new ConnectParams( | 236 std::unique_ptr<ConnectParams> params(new ConnectParams( |
| 235 device_info, callback, task_runner_, file_task_runner_)); | 237 device_info, callback, task_runner_, blocking_task_runner_)); |
| 236 | 238 |
| 237 #if defined(OS_CHROMEOS) | 239 #if defined(OS_CHROMEOS) |
| 238 chromeos::PermissionBrokerClient* client = | 240 chromeos::PermissionBrokerClient* client = |
| 239 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); | 241 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); |
| 240 DCHECK(client) << "Could not get permission broker client."; | 242 DCHECK(client) << "Could not get permission broker client."; |
| 241 chromeos::PermissionBrokerClient::ErrorCallback error_callback = | 243 chromeos::PermissionBrokerClient::ErrorCallback error_callback = |
| 242 base::Bind(&HidServiceLinux::OnPathOpenError, | 244 base::Bind(&HidServiceLinux::OnPathOpenError, |
| 243 params->device_info->device_node(), params->callback); | 245 params->device_info->device_node(), params->callback); |
| 244 client->OpenPath( | 246 client->OpenPath( |
| 245 device_info->device_node(), | 247 device_info->device_node(), |
| 246 base::Bind(&HidServiceLinux::OnPathOpenComplete, base::Passed(¶ms)), | 248 base::Bind(&HidServiceLinux::OnPathOpenComplete, base::Passed(¶ms)), |
| 247 error_callback); | 249 error_callback); |
| 248 #else | 250 #else |
| 249 file_task_runner_->PostTask(FROM_HERE, | 251 blocking_task_runner_->PostTask( |
| 250 base::Bind(&HidServiceLinux::OpenOnBlockingThread, | 252 FROM_HERE, base::Bind(&HidServiceLinux::OpenOnBlockingThread, |
| 251 base::Passed(¶ms))); | 253 base::Passed(¶ms))); |
| 252 #endif // defined(OS_CHROMEOS) | 254 #endif // defined(OS_CHROMEOS) |
| 253 } | 255 } |
| 254 | 256 |
| 255 #if defined(OS_CHROMEOS) | 257 #if defined(OS_CHROMEOS) |
| 256 | 258 |
| 257 // static | 259 // static |
| 258 void HidServiceLinux::OnPathOpenComplete(std::unique_ptr<ConnectParams> params, | 260 void HidServiceLinux::OnPathOpenComplete(std::unique_ptr<ConnectParams> params, |
| 259 base::ScopedFD fd) { | 261 base::ScopedFD fd) { |
| 260 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner = | 262 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner = |
| 261 params->file_task_runner; | 263 params->blocking_task_runner; |
| 262 params->device_file = base::File(fd.release()); | 264 params->fd = std::move(fd); |
| 263 file_task_runner->PostTask(FROM_HERE, base::Bind(&HidServiceLinux::FinishOpen, | 265 blocking_task_runner->PostTask( |
| 264 base::Passed(¶ms))); | 266 FROM_HERE, |
| 267 base::Bind(&HidServiceLinux::FinishOpen, base::Passed(¶ms))); |
| 265 } | 268 } |
| 266 | 269 |
| 267 // static | 270 // static |
| 268 void HidServiceLinux::OnPathOpenError(const std::string& device_path, | 271 void HidServiceLinux::OnPathOpenError(const std::string& device_path, |
| 269 const ConnectCallback& callback, | 272 const ConnectCallback& callback, |
| 270 const std::string& error_name, | 273 const std::string& error_name, |
| 271 const std::string& error_message) { | 274 const std::string& error_message) { |
| 272 HID_LOG(EVENT) << "Permission broker failed to open '" << device_path | 275 HID_LOG(EVENT) << "Permission broker failed to open '" << device_path |
| 273 << "': " << error_name << ": " << error_message; | 276 << "': " << error_name << ": " << error_message; |
| 274 callback.Run(nullptr); | 277 callback.Run(nullptr); |
| 275 } | 278 } |
| 276 | 279 |
| 277 #else | 280 #else |
| 278 | 281 |
| 279 // static | 282 // static |
| 280 void HidServiceLinux::OpenOnBlockingThread( | 283 void HidServiceLinux::OpenOnBlockingThread( |
| 281 std::unique_ptr<ConnectParams> params) { | 284 std::unique_ptr<ConnectParams> params) { |
| 282 base::ThreadRestrictions::AssertIOAllowed(); | 285 base::ThreadRestrictions::AssertIOAllowed(); |
| 283 scoped_refptr<base::SingleThreadTaskRunner> task_runner = params->task_runner; | 286 scoped_refptr<base::SequencedTaskRunner> task_runner = params->task_runner; |
| 284 | 287 |
| 285 base::FilePath device_path(params->device_info->device_node()); | 288 base::FilePath device_path(params->device_info->device_node()); |
| 286 base::File& device_file = params->device_file; | 289 base::File device_file; |
| 287 int flags = | 290 int flags = |
| 288 base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE; | 291 base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE; |
| 289 device_file.Initialize(device_path, flags); | 292 device_file.Initialize(device_path, flags); |
| 290 if (!device_file.IsValid()) { | 293 if (!device_file.IsValid()) { |
| 291 base::File::Error file_error = device_file.error_details(); | 294 base::File::Error file_error = device_file.error_details(); |
| 292 | 295 |
| 293 if (file_error == base::File::FILE_ERROR_ACCESS_DENIED) { | 296 if (file_error == base::File::FILE_ERROR_ACCESS_DENIED) { |
| 294 HID_LOG(EVENT) | 297 HID_LOG(EVENT) |
| 295 << "Access denied opening device read-write, trying read-only."; | 298 << "Access denied opening device read-write, trying read-only."; |
| 296 flags = base::File::FLAG_OPEN | base::File::FLAG_READ; | 299 flags = base::File::FLAG_OPEN | base::File::FLAG_READ; |
| 297 device_file.Initialize(device_path, flags); | 300 device_file.Initialize(device_path, flags); |
| 298 } | 301 } |
| 299 } | 302 } |
| 300 if (!device_file.IsValid()) { | 303 if (!device_file.IsValid()) { |
| 301 HID_LOG(EVENT) << "Failed to open '" << params->device_info->device_node() | 304 HID_LOG(EVENT) << "Failed to open '" << params->device_info->device_node() |
| 302 << "': " | 305 << "': " |
| 303 << base::File::ErrorToString(device_file.error_details()); | 306 << base::File::ErrorToString(device_file.error_details()); |
| 304 task_runner->PostTask(FROM_HERE, base::Bind(params->callback, nullptr)); | 307 task_runner->PostTask(FROM_HERE, base::Bind(params->callback, nullptr)); |
| 305 return; | 308 return; |
| 306 } | 309 } |
| 307 | 310 params->fd.reset(device_file.TakePlatformFile()); |
| 308 FinishOpen(std::move(params)); | 311 FinishOpen(std::move(params)); |
| 309 } | 312 } |
| 310 | 313 |
| 311 #endif // defined(OS_CHROMEOS) | 314 #endif // defined(OS_CHROMEOS) |
| 312 | 315 |
| 313 // static | 316 // static |
| 314 void HidServiceLinux::FinishOpen(std::unique_ptr<ConnectParams> params) { | 317 void HidServiceLinux::FinishOpen(std::unique_ptr<ConnectParams> params) { |
| 315 base::ThreadRestrictions::AssertIOAllowed(); | 318 base::ThreadRestrictions::AssertIOAllowed(); |
| 316 scoped_refptr<base::SingleThreadTaskRunner> task_runner = params->task_runner; | 319 scoped_refptr<base::SequencedTaskRunner> task_runner = params->task_runner; |
| 317 | 320 |
| 318 if (!base::SetNonBlocking(params->device_file.GetPlatformFile())) { | 321 if (!base::SetNonBlocking(params->fd.get())) { |
| 319 HID_PLOG(ERROR) << "Failed to set the non-blocking flag on the device fd"; | 322 HID_PLOG(ERROR) << "Failed to set the non-blocking flag on the device fd"; |
| 320 task_runner->PostTask(FROM_HERE, base::Bind(params->callback, nullptr)); | 323 task_runner->PostTask(FROM_HERE, base::Bind(params->callback, nullptr)); |
| 321 return; | 324 return; |
| 322 } | 325 } |
| 323 | 326 |
| 324 task_runner->PostTask( | 327 task_runner->PostTask( |
| 325 FROM_HERE, | 328 FROM_HERE, |
| 326 base::Bind(&HidServiceLinux::CreateConnection, base::Passed(¶ms))); | 329 base::Bind(&HidServiceLinux::CreateConnection, base::Passed(¶ms))); |
| 327 } | 330 } |
| 328 | 331 |
| 329 // static | 332 // static |
| 330 void HidServiceLinux::CreateConnection(std::unique_ptr<ConnectParams> params) { | 333 void HidServiceLinux::CreateConnection(std::unique_ptr<ConnectParams> params) { |
| 331 DCHECK(params->device_file.IsValid()); | 334 DCHECK(params->fd.is_valid()); |
| 332 params->callback.Run(make_scoped_refptr(new HidConnectionLinux( | 335 params->callback.Run(make_scoped_refptr(new HidConnectionLinux( |
| 333 params->device_info, std::move(params->device_file), | 336 std::move(params->device_info), std::move(params->fd), |
| 334 params->file_task_runner))); | 337 std::move(params->blocking_task_runner)))); |
| 335 } | 338 } |
| 336 | 339 |
| 337 } // namespace device | 340 } // namespace device |
| OLD | NEW |