1 // Copyright 2015 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/devices_app/usb/device_manager_impl.h"
8 #include "base/location.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/scoped_observer.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "device/core/device_client.h"
16 #include "device/devices_app/usb/device_impl.h"
17 #include "device/devices_app/usb/public/interfaces/device.mojom.h"
18 #include "device/devices_app/usb/type_converters.h"
19 #include "device/usb/usb_device.h"
20 #include "device/usb/usb_device_filter.h"
21 #include "device/usb/usb_service.h"
22 #include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
23 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
30 using DeviceList
= DeviceManagerImpl::DeviceList
;
31 using DeviceMap
= DeviceManagerImpl::DeviceMap
;
33 void OnGetDevicesOnServiceThread(
34 const base::Callback
<void(const DeviceList
&)>& callback
,
35 scoped_refptr
<base::TaskRunner
> callback_task_runner
,
36 const DeviceList
& devices
) {
37 callback_task_runner
->PostTask(FROM_HERE
, base::Bind(callback
, devices
));
40 void GetDevicesOnServiceThread(
41 const base::Callback
<void(const DeviceList
&)>& callback
,
42 scoped_refptr
<base::TaskRunner
> callback_task_runner
) {
43 DCHECK(DeviceClient::Get());
44 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
46 usb_service
->GetDevices(base::Bind(&OnGetDevicesOnServiceThread
, callback
,
47 callback_task_runner
));
49 callback_task_runner
->PostTask(FROM_HERE
,
50 base::Bind(callback
, DeviceList()));
54 void GetDeviceOnServiceThread(
55 const mojo::String
& guid
,
56 const base::Callback
<void(DeviceInfoPtr
)>& callback
,
57 scoped_refptr
<base::TaskRunner
> callback_task_runner
) {
58 DeviceInfoPtr device_info
;
59 DCHECK(DeviceClient::Get());
60 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
62 scoped_refptr
<UsbDevice
> device
= usb_service
->GetDevice(guid
);
64 device_info
= DeviceInfo::From(*device
);
67 callback_task_runner
->PostTask(
68 FROM_HERE
, base::Bind(callback
, base::Passed(&device_info
)));
71 void RunOpenDeviceCallback(const DeviceManager::OpenDeviceCallback
& callback
,
72 OpenDeviceError error
) {
76 void OnOpenDeviceOnServiceThread(
77 mojo::InterfaceRequest
<Device
> device_request
,
78 const DeviceManager::OpenDeviceCallback
& callback
,
79 scoped_refptr
<base::TaskRunner
> callback_task_runner
,
80 scoped_refptr
<UsbDeviceHandle
> device_handle
) {
82 callback_task_runner
->PostTask(FROM_HERE
,
83 base::Bind(&RunOpenDeviceCallback
, callback
,
84 OPEN_DEVICE_ERROR_ACCESS_DENIED
));
88 // Owned by its MessagePipe.
89 new DeviceImpl(device_handle
, device_request
.Pass());
91 callback_task_runner
->PostTask(
93 base::Bind(&RunOpenDeviceCallback
, callback
, OPEN_DEVICE_ERROR_OK
));
96 void OpenDeviceOnServiceThread(
97 const std::string
& guid
,
98 mojo::InterfaceRequest
<Device
> device_request
,
99 const DeviceManager::OpenDeviceCallback
& callback
,
100 scoped_refptr
<base::TaskRunner
> callback_task_runner
) {
101 DCHECK(DeviceClient::Get());
102 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
104 callback_task_runner
->PostTask(FROM_HERE
,
105 base::Bind(&RunOpenDeviceCallback
, callback
,
106 OPEN_DEVICE_ERROR_NOT_FOUND
));
109 scoped_refptr
<UsbDevice
> device
= usb_service
->GetDevice(guid
);
111 callback_task_runner
->PostTask(FROM_HERE
,
112 base::Bind(&RunOpenDeviceCallback
, callback
,
113 OPEN_DEVICE_ERROR_NOT_FOUND
));
116 device
->Open(base::Bind(&OnOpenDeviceOnServiceThread
,
117 base::Passed(&device_request
), callback
,
118 callback_task_runner
));
121 void FilterAndConvertDevicesAndThen(
122 const DeviceMap
& devices
,
123 const DeviceManagerImpl::GetDevicesCallback
& callback
,
124 mojo::Array
<mojo::String
> allowed_guids
) {
125 mojo::Array
<DeviceInfoPtr
> allowed_devices(allowed_guids
.size());
126 for (size_t i
= 0; i
< allowed_guids
.size(); ++i
) {
127 const auto it
= devices
.find(allowed_guids
[i
]);
128 DCHECK(it
!= devices
.end());
129 allowed_devices
[i
] = DeviceInfo::From(*it
->second
);
132 callback
.Run(allowed_devices
.Pass());
137 class DeviceManagerImpl::ServiceThreadHelper
138 : public UsbService::Observer
,
139 public base::MessageLoop::DestructionObserver
{
141 ServiceThreadHelper(base::WeakPtr
<DeviceManagerImpl
> manager
,
142 scoped_refptr
<base::TaskRunner
> task_runner
)
143 : observer_(this), manager_(manager
), task_runner_(task_runner
) {}
145 ~ServiceThreadHelper() override
{
146 base::MessageLoop::current()->RemoveDestructionObserver(this);
149 static void Start(scoped_ptr
<ServiceThreadHelper
> self
) {
150 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
152 self
->observer_
.Add(usb_service
);
154 // |self| now owned by the current message loop.
155 base::MessageLoop::current()->AddDestructionObserver(self
.release());
159 // UsbService::Observer
160 void OnDeviceAdded(scoped_refptr
<UsbDevice
> device
) override
{
161 task_runner_
->PostTask(
163 base::Bind(&DeviceManagerImpl::OnDeviceAdded
, manager_
, device
));
166 void OnDeviceRemoved(scoped_refptr
<UsbDevice
> device
) override
{
167 task_runner_
->PostTask(
169 base::Bind(&DeviceManagerImpl::OnDeviceRemoved
, manager_
, device
));
172 void WillDestroyUsbService() override
{ observer_
.RemoveAll(); }
174 // base::MessageLoop::DestructionObserver
175 void WillDestroyCurrentMessageLoop() override
{ delete this; }
177 ScopedObserver
<UsbService
, UsbService::Observer
> observer_
;
178 base::WeakPtr
<DeviceManagerImpl
> manager_
;
179 scoped_refptr
<base::TaskRunner
> task_runner_
;
182 DeviceManagerImpl::DeviceManagerImpl(
183 mojo::InterfaceRequest
<DeviceManager
> request
,
184 PermissionProviderPtr permission_provider
,
185 scoped_refptr
<base::SequencedTaskRunner
> service_task_runner
)
186 : permission_provider_(permission_provider
.Pass()),
187 service_task_runner_(service_task_runner
),
188 binding_(this, request
.Pass()),
189 weak_factory_(this) {
190 // This object owns itself and will be destroyed if either the message pipe
191 // it is bound to is closed or the PermissionProvider it depends on is
193 binding_
.set_connection_error_handler([this]() { delete this; });
194 permission_provider_
.set_connection_error_handler([this]() { delete this; });
196 scoped_ptr
<ServiceThreadHelper
> helper(new ServiceThreadHelper(
197 weak_factory_
.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get()));
198 helper_
= helper
.get();
199 service_task_runner_
->PostTask(
201 base::Bind(&ServiceThreadHelper::Start
, base::Passed(&helper
)));
204 DeviceManagerImpl::~DeviceManagerImpl() {
205 // It is safe to call this if |helper_| was already destroyed when
206 // |service_task_runner_| exited as the task will never execute.
207 service_task_runner_
->DeleteSoon(FROM_HERE
, helper_
);
208 connection_error_handler_
.Run();
211 void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options
,
212 const GetDevicesCallback
& callback
) {
213 auto get_devices_callback
=
214 base::Bind(&DeviceManagerImpl::OnGetDevices
, weak_factory_
.GetWeakPtr(),
215 base::Passed(&options
), callback
);
216 service_task_runner_
->PostTask(
217 FROM_HERE
, base::Bind(&GetDevicesOnServiceThread
, get_devices_callback
,
218 base::ThreadTaskRunnerHandle::Get()));
221 void DeviceManagerImpl::GetDeviceChanges(
222 const GetDeviceChangesCallback
& callback
) {
223 device_change_callbacks_
.push(callback
);
224 MaybeRunDeviceChangesCallback();
227 void DeviceManagerImpl::OpenDevice(
228 const mojo::String
& guid
,
229 mojo::InterfaceRequest
<Device
> device_request
,
230 const OpenDeviceCallback
& callback
) {
231 auto has_permission_callback
= base::Bind(
232 &DeviceManagerImpl::OnGotDeviceInfoForOpen
, weak_factory_
.GetWeakPtr(),
233 base::Passed(&device_request
), callback
);
234 service_task_runner_
->PostTask(
236 base::Bind(&GetDeviceOnServiceThread
, guid
, has_permission_callback
,
237 base::ThreadTaskRunnerHandle::Get()));
240 void DeviceManagerImpl::OnGotDeviceInfoForOpen(
241 mojo::InterfaceRequest
<Device
> device_request
,
242 const OpenDeviceCallback
& callback
,
243 DeviceInfoPtr device_info
) {
245 callback
.Run(OPEN_DEVICE_ERROR_NOT_FOUND
);
249 mojo::Array
<DeviceInfoPtr
> requested_devices(1);
250 requested_devices
[0] = device_info
.Pass();
251 permission_provider_
->HasDevicePermission(
252 requested_devices
.Pass(),
253 base::Bind(&DeviceManagerImpl::OnOpenDevicePermissionCheckComplete
,
254 base::Unretained(this), base::Passed(&device_request
),
258 void DeviceManagerImpl::OnOpenDevicePermissionCheckComplete(
259 mojo::InterfaceRequest
<Device
> device_request
,
260 const OpenDeviceCallback
& callback
,
261 mojo::Array
<mojo::String
> allowed_guids
) {
262 if (allowed_guids
.size() == 0) {
263 callback
.Run(OPEN_DEVICE_ERROR_ACCESS_DENIED
);
267 DCHECK(allowed_guids
.size() == 1);
268 service_task_runner_
->PostTask(
269 FROM_HERE
, base::Bind(&OpenDeviceOnServiceThread
, allowed_guids
[0],
270 base::Passed(&device_request
), callback
,
271 base::ThreadTaskRunnerHandle::Get()));
274 void DeviceManagerImpl::OnGetDevices(EnumerationOptionsPtr options
,
275 const GetDevicesCallback
& callback
,
276 const DeviceList
& devices
) {
277 std::vector
<UsbDeviceFilter
> filters
;
279 filters
= options
->filters
.To
<std::vector
<UsbDeviceFilter
>>();
281 std::map
<std::string
, scoped_refptr
<UsbDevice
>> device_map
;
282 mojo::Array
<DeviceInfoPtr
> requested_devices(0);
283 for (const auto& device
: devices
) {
284 if (filters
.empty() || UsbDeviceFilter::MatchesAny(device
, filters
)) {
285 device_map
[device
->guid()] = device
;
286 requested_devices
.push_back(DeviceInfo::From(*device
));
290 permission_provider_
->HasDevicePermission(
291 requested_devices
.Pass(),
292 base::Bind(&FilterAndConvertDevicesAndThen
, device_map
, callback
));
295 void DeviceManagerImpl::OnDeviceAdded(scoped_refptr
<UsbDevice
> device
) {
296 DCHECK(!ContainsKey(devices_removed_
, device
->guid()));
297 devices_added_
[device
->guid()] = device
;
298 MaybeRunDeviceChangesCallback();
301 void DeviceManagerImpl::OnDeviceRemoved(scoped_refptr
<UsbDevice
> device
) {
302 if (devices_added_
.erase(device
->guid()) == 0)
303 devices_removed_
[device
->guid()] = device
;
304 MaybeRunDeviceChangesCallback();
307 void DeviceManagerImpl::MaybeRunDeviceChangesCallback() {
308 if (!permission_request_pending_
&& !device_change_callbacks_
.empty()) {
309 DeviceMap devices_added
;
310 devices_added
.swap(devices_added_
);
311 DeviceMap devices_removed
;
312 devices_removed
.swap(devices_removed_
);
314 mojo::Array
<DeviceInfoPtr
> requested_devices(devices_added
.size() +
315 devices_removed
.size());
318 for (const auto& map_entry
: devices_added
)
319 requested_devices
[i
++] = DeviceInfo::From(*map_entry
.second
);
320 for (const auto& map_entry
: devices_removed
)
321 requested_devices
[i
++] = DeviceInfo::From(*map_entry
.second
);
324 permission_request_pending_
= true;
325 permission_provider_
->HasDevicePermission(
326 requested_devices
.Pass(),
327 base::Bind(&DeviceManagerImpl::OnEnumerationPermissionCheckComplete
,
328 base::Unretained(this), devices_added
, devices_removed
));
332 void DeviceManagerImpl::OnEnumerationPermissionCheckComplete(
333 const DeviceMap
& devices_added
,
334 const DeviceMap
& devices_removed
,
335 mojo::Array
<mojo::String
> allowed_guids
) {
336 permission_request_pending_
= false;
338 if (allowed_guids
.size() > 0) {
339 DeviceChangeNotificationPtr notification
= DeviceChangeNotification::New();
340 notification
->devices_added
.resize(0);
341 notification
->devices_removed
.resize(0);
343 for (size_t i
= 0; i
< allowed_guids
.size(); ++i
) {
344 const mojo::String
& guid
= allowed_guids
[i
];
345 auto it
= devices_added
.find(guid
);
346 if (it
!= devices_added
.end()) {
347 DCHECK(!ContainsKey(devices_removed
, guid
));
348 notification
->devices_added
.push_back(DeviceInfo::From(*it
->second
));
350 it
= devices_removed
.find(guid
);
351 DCHECK(it
!= devices_removed
.end());
352 notification
->devices_removed
.push_back(DeviceInfo::From(*it
->second
));
356 DCHECK(!device_change_callbacks_
.empty());
357 const GetDeviceChangesCallback
& callback
= device_change_callbacks_
.front();
358 callback
.Run(notification
.Pass());
359 device_change_callbacks_
.pop();
362 if (devices_added_
.size() > 0 || !devices_removed_
.empty())
363 MaybeRunDeviceChangesCallback();
367 } // namespace device