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/cpp/device_manager_delegate.h"
18 #include "device/devices_app/usb/public/interfaces/device.mojom.h"
19 #include "device/devices_app/usb/type_converters.h"
20 #include "device/usb/usb_device.h"
21 #include "device/usb/usb_device_filter.h"
22 #include "device/usb/usb_service.h"
23 #include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
24 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
31 void OnGetDevicesOnServiceThread(
32 const std::vector
<UsbDeviceFilter
>& filters
,
33 const base::Callback
<void(mojo::Array
<DeviceInfoPtr
>)>& callback
,
34 scoped_refptr
<base::TaskRunner
> callback_task_runner
,
35 const std::vector
<scoped_refptr
<UsbDevice
>>& devices
) {
36 mojo::Array
<DeviceInfoPtr
> mojo_devices(0);
37 for (size_t i
= 0; i
< devices
.size(); ++i
) {
38 if (UsbDeviceFilter::MatchesAny(devices
[i
], filters
) || filters
.empty())
39 mojo_devices
.push_back(DeviceInfo::From(*devices
[i
]));
41 callback_task_runner
->PostTask(
42 FROM_HERE
, base::Bind(callback
, base::Passed(&mojo_devices
)));
45 void GetDevicesOnServiceThread(
46 const std::vector
<UsbDeviceFilter
>& filters
,
47 const base::Callback
<void(mojo::Array
<DeviceInfoPtr
>)>& callback
,
48 scoped_refptr
<base::TaskRunner
> callback_task_runner
) {
49 DCHECK(DeviceClient::Get());
50 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
52 mojo::Array
<DeviceInfoPtr
> no_devices(0);
53 callback_task_runner
->PostTask(
54 FROM_HERE
, base::Bind(callback
, base::Passed(&no_devices
)));
57 usb_service
->GetDevices(base::Bind(&OnGetDevicesOnServiceThread
, filters
,
58 callback
, callback_task_runner
));
61 void RunOpenDeviceCallback(const DeviceManager::OpenDeviceCallback
& callback
,
62 OpenDeviceError error
) {
66 void OnOpenDeviceOnServiceThread(
67 mojo::InterfaceRequest
<Device
> device_request
,
68 const DeviceManager::OpenDeviceCallback
& callback
,
69 scoped_refptr
<base::TaskRunner
> callback_task_runner
,
70 scoped_refptr
<UsbDeviceHandle
> device_handle
) {
72 callback_task_runner
->PostTask(FROM_HERE
,
73 base::Bind(&RunOpenDeviceCallback
, callback
,
74 OPEN_DEVICE_ERROR_ACCESS_DENIED
));
78 // Owned by its MessagePipe.
79 new DeviceImpl(device_handle
, device_request
.Pass());
81 callback_task_runner
->PostTask(
83 base::Bind(&RunOpenDeviceCallback
, callback
, OPEN_DEVICE_ERROR_OK
));
86 void OpenDeviceOnServiceThread(
87 const std::string
& guid
,
88 mojo::InterfaceRequest
<Device
> device_request
,
89 const DeviceManager::OpenDeviceCallback
& callback
,
90 scoped_refptr
<base::TaskRunner
> callback_task_runner
) {
91 DCHECK(DeviceClient::Get());
92 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
94 callback_task_runner
->PostTask(FROM_HERE
,
95 base::Bind(&RunOpenDeviceCallback
, callback
,
96 OPEN_DEVICE_ERROR_NOT_FOUND
));
99 scoped_refptr
<UsbDevice
> device
= usb_service
->GetDevice(guid
);
101 callback_task_runner
->PostTask(FROM_HERE
,
102 base::Bind(&RunOpenDeviceCallback
, callback
,
103 OPEN_DEVICE_ERROR_NOT_FOUND
));
106 device
->Open(base::Bind(&OnOpenDeviceOnServiceThread
,
107 base::Passed(&device_request
), callback
,
108 callback_task_runner
));
113 class DeviceManagerImpl::ServiceThreadHelper
114 : public UsbService::Observer
,
115 public base::MessageLoop::DestructionObserver
{
117 ServiceThreadHelper(base::WeakPtr
<DeviceManagerImpl
> manager
,
118 scoped_refptr
<base::TaskRunner
> task_runner
)
119 : observer_(this), manager_(manager
), task_runner_(task_runner
) {}
121 ~ServiceThreadHelper() override
{
122 base::MessageLoop::current()->RemoveDestructionObserver(this);
126 scoped_ptr
<ServiceThreadHelper
> self
,
127 const base::Callback
<void(mojo::Array
<DeviceInfoPtr
>)>& callback
) {
128 UsbService
* usb_service
= DeviceClient::Get()->GetUsbService();
130 self
->observer_
.Add(usb_service
);
131 std::vector
<UsbDeviceFilter
> no_filters
;
132 usb_service
->GetDevices(base::Bind(&OnGetDevicesOnServiceThread
,
133 no_filters
, callback
,
134 self
->task_runner_
));
137 // |self| now owned by the current message loop.
138 base::MessageLoop::current()->AddDestructionObserver(self
.release());
142 // UsbService::Observer
143 void OnDeviceAdded(scoped_refptr
<UsbDevice
> device
) override
{
144 DeviceInfoPtr
mojo_device(DeviceInfo::From(*device
));
145 task_runner_
->PostTask(
146 FROM_HERE
, base::Bind(&DeviceManagerImpl::OnDeviceAdded
, manager_
,
147 base::Passed(&mojo_device
)));
150 void OnDeviceRemoved(scoped_refptr
<UsbDevice
> device
) override
{
151 task_runner_
->PostTask(
152 FROM_HERE
, base::Bind(&DeviceManagerImpl::OnDeviceRemoved
, manager_
,
156 // base::MessageLoop::DestructionObserver
157 void WillDestroyCurrentMessageLoop() override
{ delete this; }
159 ScopedObserver
<UsbService
, UsbService::Observer
> observer_
;
160 base::WeakPtr
<DeviceManagerImpl
> manager_
;
161 scoped_refptr
<base::TaskRunner
> task_runner_
;
164 DeviceManagerImpl::DeviceManagerImpl(
165 mojo::InterfaceRequest
<DeviceManager
> request
,
166 scoped_ptr
<DeviceManagerDelegate
> delegate
,
167 scoped_refptr
<base::SequencedTaskRunner
> service_task_runner
)
168 : binding_(this, request
.Pass()),
169 delegate_(delegate
.Pass()),
170 service_task_runner_(service_task_runner
),
171 weak_factory_(this) {
174 DeviceManagerImpl::~DeviceManagerImpl() {
176 // It is safe to call this if |helper_| was already destroyed when
177 // |service_task_runner_| exited as the task will never execute.
178 service_task_runner_
->DeleteSoon(FROM_HERE
, helper_
);
182 void DeviceManagerImpl::set_connection_error_handler(
183 const mojo::Closure
& error_handler
) {
184 binding_
.set_connection_error_handler(error_handler
);
187 void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options
,
188 const GetDevicesCallback
& callback
) {
189 auto filters
= options
->filters
.To
<std::vector
<UsbDeviceFilter
>>();
190 auto get_devices_callback
= base::Bind(&DeviceManagerImpl::OnGetDevices
,
191 weak_factory_
.GetWeakPtr(), callback
);
192 service_task_runner_
->PostTask(
194 base::Bind(&GetDevicesOnServiceThread
, filters
, get_devices_callback
,
195 base::ThreadTaskRunnerHandle::Get()));
198 void DeviceManagerImpl::GetDeviceChanges(
199 const GetDeviceChangesCallback
& callback
) {
201 device_change_callbacks_
.push(callback
);
202 MaybeRunDeviceChangesCallback();
204 scoped_ptr
<ServiceThreadHelper
> helper(new ServiceThreadHelper(
205 weak_factory_
.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get()));
206 helper_
= helper
.get();
207 auto get_devices_callback
=
208 base::Bind(&DeviceManagerImpl::OnGetInitialDevices
,
209 weak_factory_
.GetWeakPtr(), callback
);
210 service_task_runner_
->PostTask(
211 FROM_HERE
, base::Bind(&ServiceThreadHelper::Start
,
212 base::Passed(&helper
), get_devices_callback
));
216 void DeviceManagerImpl::OpenDevice(
217 const mojo::String
& guid
,
218 mojo::InterfaceRequest
<Device
> device_request
,
219 const OpenDeviceCallback
& callback
) {
220 service_task_runner_
->PostTask(
221 FROM_HERE
, base::Bind(&OpenDeviceOnServiceThread
, guid
,
222 base::Passed(&device_request
), callback
,
223 base::ThreadTaskRunnerHandle::Get()));
226 void DeviceManagerImpl::OnGetDevices(const GetDevicesCallback
& callback
,
227 mojo::Array
<DeviceInfoPtr
> devices
) {
228 mojo::Array
<DeviceInfoPtr
> allowed_devices(0);
229 for (size_t i
= 0; i
< devices
.size(); ++i
) {
230 if (delegate_
->IsDeviceAllowed(*devices
[i
]))
231 allowed_devices
.push_back(devices
[i
].Pass());
233 callback
.Run(allowed_devices
.Pass());
236 void DeviceManagerImpl::OnGetInitialDevices(
237 const GetDeviceChangesCallback
& callback
,
238 mojo::Array
<DeviceInfoPtr
> devices
) {
239 DeviceChangeNotificationPtr notification
= DeviceChangeNotification::New();
240 notification
->devices_added
= mojo::Array
<DeviceInfoPtr
>::New(0);
241 notification
->devices_removed
= mojo::Array
<mojo::String
>::New(0);
242 for (size_t i
= 0; i
< devices
.size(); ++i
) {
243 if (delegate_
->IsDeviceAllowed(*devices
[i
]))
244 notification
->devices_added
.push_back(devices
[i
].Pass());
246 callback
.Run(notification
.Pass());
249 void DeviceManagerImpl::OnDeviceAdded(DeviceInfoPtr device
) {
250 DCHECK(!ContainsKey(devices_removed_
, device
->guid
));
251 devices_added_
.push_back(device
.Pass());
252 MaybeRunDeviceChangesCallback();
255 void DeviceManagerImpl::OnDeviceRemoved(std::string device_guid
) {
257 mojo::Array
<DeviceInfoPtr
> devices_added
;
258 for (size_t i
= 0; i
< devices_added_
.size(); ++i
) {
259 if (devices_added_
[i
]->guid
== device_guid
)
262 devices_added
.push_back(devices_added_
[i
].Pass());
264 devices_added
.Swap(&devices_added_
);
266 devices_removed_
.insert(device_guid
);
267 MaybeRunDeviceChangesCallback();
270 void DeviceManagerImpl::MaybeRunDeviceChangesCallback() {
271 if (!device_change_callbacks_
.empty()) {
272 DeviceChangeNotificationPtr notification
= DeviceChangeNotification::New();
273 notification
->devices_added
.Swap(&devices_added_
);
274 notification
->devices_removed
.resize(0);
275 for (const std::string
& device
: devices_removed_
)
276 notification
->devices_removed
.push_back(device
);
277 devices_removed_
.clear();
279 const GetDeviceChangesCallback
& callback
= device_change_callbacks_
.front();
280 callback
.Run(notification
.Pass());
281 device_change_callbacks_
.pop();
286 } // namespace device