OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "device/devices_app/usb/device_manager_impl.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <utility> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/location.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/stl_util.h" | |
14 #include "device/core/device_client.h" | |
15 #include "device/devices_app/usb/device_impl.h" | |
16 #include "device/devices_app/usb/public/interfaces/device.mojom.h" | |
17 #include "device/devices_app/usb/type_converters.h" | |
18 #include "device/usb/usb_device.h" | |
19 #include "device/usb/usb_device_filter.h" | |
20 #include "device/usb/usb_service.h" | |
21 #include "mojo/public/cpp/bindings/array.h" | |
22 #include "mojo/public/cpp/bindings/interface_request.h" | |
23 | |
24 namespace device { | |
25 namespace usb { | |
26 | |
27 namespace { | |
28 | |
29 using DeviceList = DeviceManagerImpl::DeviceList; | |
30 using DeviceMap = DeviceManagerImpl::DeviceMap; | |
31 | |
32 void FilterAndConvertDevicesAndThen( | |
33 const DeviceMap& devices, | |
34 const DeviceManagerImpl::GetDevicesCallback& callback, | |
35 mojo::Array<mojo::String> allowed_guids) { | |
36 mojo::Array<DeviceInfoPtr> allowed_devices(allowed_guids.size()); | |
37 for (size_t i = 0; i < allowed_guids.size(); ++i) { | |
38 const auto it = devices.find(allowed_guids[i]); | |
39 DCHECK(it != devices.end()); | |
40 allowed_devices[i] = DeviceInfo::From(*it->second); | |
41 } | |
42 | |
43 callback.Run(std::move(allowed_devices)); | |
44 } | |
45 | |
46 } // namespace | |
47 | |
48 // static | |
49 void DeviceManagerImpl::Create(PermissionProviderPtr permission_provider, | |
50 mojo::InterfaceRequest<DeviceManager> request) { | |
51 // The created object is owned by its binding. | |
52 new DeviceManagerImpl(std::move(permission_provider), std::move(request)); | |
53 } | |
54 | |
55 DeviceManagerImpl::DeviceManagerImpl( | |
56 PermissionProviderPtr permission_provider, | |
57 mojo::InterfaceRequest<DeviceManager> request) | |
58 : permission_provider_(std::move(permission_provider)), | |
59 observer_(this), | |
60 binding_(this, std::move(request)), | |
61 weak_factory_(this) { | |
62 // This object owns itself and will be destroyed if either the message pipe | |
63 // it is bound to is closed or the PermissionProvider it depends on is | |
64 // unavailable. | |
65 binding_.set_connection_error_handler([this]() { delete this; }); | |
66 permission_provider_.set_connection_error_handler([this]() { delete this; }); | |
67 | |
68 DCHECK(DeviceClient::Get()); | |
69 usb_service_ = DeviceClient::Get()->GetUsbService(); | |
70 if (usb_service_) | |
71 observer_.Add(usb_service_); | |
72 } | |
73 | |
74 DeviceManagerImpl::~DeviceManagerImpl() { | |
75 connection_error_handler_.Run(); | |
76 } | |
77 | |
78 void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options, | |
79 const GetDevicesCallback& callback) { | |
80 if (!usb_service_) { | |
81 mojo::Array<DeviceInfoPtr> no_devices; | |
82 callback.Run(std::move(no_devices)); | |
83 return; | |
84 } | |
85 | |
86 usb_service_->GetDevices(base::Bind(&DeviceManagerImpl::OnGetDevices, | |
87 weak_factory_.GetWeakPtr(), | |
88 base::Passed(&options), callback)); | |
89 } | |
90 | |
91 void DeviceManagerImpl::GetDeviceChanges( | |
92 const GetDeviceChangesCallback& callback) { | |
93 device_change_callbacks_.push(callback); | |
94 MaybeRunDeviceChangesCallback(); | |
95 } | |
96 | |
97 void DeviceManagerImpl::GetDevice( | |
98 const mojo::String& guid, | |
99 mojo::InterfaceRequest<Device> device_request) { | |
100 if (!usb_service_) | |
101 return; | |
102 | |
103 scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid); | |
104 if (!device) | |
105 return; | |
106 | |
107 mojo::Array<DeviceInfoPtr> requested_devices(1); | |
108 requested_devices[0] = DeviceInfo::From(*device); | |
109 permission_provider_->HasDevicePermission( | |
110 std::move(requested_devices), | |
111 base::Bind(&DeviceManagerImpl::OnGetDevicePermissionCheckComplete, | |
112 base::Unretained(this), device, | |
113 base::Passed(&device_request))); | |
114 } | |
115 | |
116 void DeviceManagerImpl::OnGetDevicePermissionCheckComplete( | |
117 scoped_refptr<UsbDevice> device, | |
118 mojo::InterfaceRequest<Device> device_request, | |
119 mojo::Array<mojo::String> allowed_guids) { | |
120 if (allowed_guids.size() == 0) | |
121 return; | |
122 | |
123 DCHECK(allowed_guids.size() == 1); | |
124 PermissionProviderPtr permission_provider; | |
125 permission_provider_->Bind(mojo::GetProxy(&permission_provider)); | |
126 new DeviceImpl(device, std::move(permission_provider), | |
127 std::move(device_request)); | |
128 } | |
129 | |
130 void DeviceManagerImpl::OnGetDevices(EnumerationOptionsPtr options, | |
131 const GetDevicesCallback& callback, | |
132 const DeviceList& devices) { | |
133 std::vector<UsbDeviceFilter> filters; | |
134 if (options) | |
135 filters = options->filters.To<std::vector<UsbDeviceFilter>>(); | |
136 | |
137 std::map<std::string, scoped_refptr<UsbDevice>> device_map; | |
138 mojo::Array<DeviceInfoPtr> requested_devices(0); | |
139 for (const auto& device : devices) { | |
140 if (filters.empty() || UsbDeviceFilter::MatchesAny(device, filters)) { | |
141 device_map[device->guid()] = device; | |
142 requested_devices.push_back(DeviceInfo::From(*device)); | |
143 } | |
144 } | |
145 | |
146 permission_provider_->HasDevicePermission( | |
147 std::move(requested_devices), | |
148 base::Bind(&FilterAndConvertDevicesAndThen, device_map, callback)); | |
149 } | |
150 | |
151 void DeviceManagerImpl::OnDeviceAdded(scoped_refptr<UsbDevice> device) { | |
152 DCHECK(!ContainsKey(devices_removed_, device->guid())); | |
153 devices_added_[device->guid()] = device; | |
154 MaybeRunDeviceChangesCallback(); | |
155 } | |
156 | |
157 void DeviceManagerImpl::OnDeviceRemoved(scoped_refptr<UsbDevice> device) { | |
158 if (devices_added_.erase(device->guid()) == 0) | |
159 devices_removed_[device->guid()] = device; | |
160 MaybeRunDeviceChangesCallback(); | |
161 } | |
162 | |
163 void DeviceManagerImpl::WillDestroyUsbService() { | |
164 observer_.RemoveAll(); | |
165 usb_service_ = nullptr; | |
166 } | |
167 | |
168 void DeviceManagerImpl::MaybeRunDeviceChangesCallback() { | |
169 if (!permission_request_pending_ && !device_change_callbacks_.empty()) { | |
170 DeviceMap devices_added; | |
171 devices_added.swap(devices_added_); | |
172 DeviceMap devices_removed; | |
173 devices_removed.swap(devices_removed_); | |
174 | |
175 mojo::Array<DeviceInfoPtr> requested_devices(devices_added.size() + | |
176 devices_removed.size()); | |
177 { | |
178 size_t i = 0; | |
179 for (const auto& map_entry : devices_added) | |
180 requested_devices[i++] = DeviceInfo::From(*map_entry.second); | |
181 for (const auto& map_entry : devices_removed) | |
182 requested_devices[i++] = DeviceInfo::From(*map_entry.second); | |
183 } | |
184 | |
185 permission_request_pending_ = true; | |
186 permission_provider_->HasDevicePermission( | |
187 std::move(requested_devices), | |
188 base::Bind(&DeviceManagerImpl::OnEnumerationPermissionCheckComplete, | |
189 base::Unretained(this), devices_added, devices_removed)); | |
190 } | |
191 } | |
192 | |
193 void DeviceManagerImpl::OnEnumerationPermissionCheckComplete( | |
194 const DeviceMap& devices_added, | |
195 const DeviceMap& devices_removed, | |
196 mojo::Array<mojo::String> allowed_guids) { | |
197 permission_request_pending_ = false; | |
198 | |
199 if (allowed_guids.size() > 0) { | |
200 DeviceChangeNotificationPtr notification = DeviceChangeNotification::New(); | |
201 notification->devices_added.resize(0); | |
202 notification->devices_removed.resize(0); | |
203 | |
204 for (size_t i = 0; i < allowed_guids.size(); ++i) { | |
205 const mojo::String& guid = allowed_guids[i]; | |
206 auto it = devices_added.find(guid); | |
207 if (it != devices_added.end()) { | |
208 DCHECK(!ContainsKey(devices_removed, guid)); | |
209 notification->devices_added.push_back(DeviceInfo::From(*it->second)); | |
210 } else { | |
211 it = devices_removed.find(guid); | |
212 DCHECK(it != devices_removed.end()); | |
213 notification->devices_removed.push_back(DeviceInfo::From(*it->second)); | |
214 } | |
215 } | |
216 | |
217 DCHECK(!device_change_callbacks_.empty()); | |
218 const GetDeviceChangesCallback& callback = device_change_callbacks_.front(); | |
219 callback.Run(std::move(notification)); | |
220 device_change_callbacks_.pop(); | |
221 } | |
222 | |
223 if (devices_added_.size() > 0 || !devices_removed_.empty()) | |
224 MaybeRunDeviceChangesCallback(); | |
225 } | |
226 | |
227 } // namespace usb | |
228 } // namespace device | |
OLD | NEW |