Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_device_manager.cc
blob560ce67344655639423259688e2dda410ea25769
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 "extensions/browser/api/hid/hid_device_manager.h"
7 #include <limits>
8 #include <vector>
10 #include "base/lazy_instance.h"
11 #include "device/core/device_client.h"
12 #include "device/hid/hid_device_filter.h"
13 #include "device/hid/hid_service.h"
14 #include "extensions/browser/api/device_permissions_manager.h"
15 #include "extensions/common/permissions/permissions_data.h"
16 #include "extensions/common/permissions/usb_device_permission.h"
18 namespace hid = extensions::api::hid;
20 using device::HidDeviceFilter;
21 using device::HidDeviceId;
22 using device::HidDeviceInfo;
23 using device::HidService;
25 namespace extensions {
27 namespace {
29 void PopulateHidDeviceInfo(hid::HidDeviceInfo* output,
30 scoped_refptr<const HidDeviceInfo> input) {
31 output->vendor_id = input->vendor_id();
32 output->product_id = input->product_id();
33 output->product_name = input->product_name();
34 output->serial_number = input->serial_number();
35 output->max_input_report_size = input->max_input_report_size();
36 output->max_output_report_size = input->max_output_report_size();
37 output->max_feature_report_size = input->max_feature_report_size();
39 for (const device::HidCollectionInfo& collection : input->collections()) {
40 // Don't expose sensitive data.
41 if (collection.usage.IsProtected()) {
42 continue;
45 hid::HidCollectionInfo* api_collection = new hid::HidCollectionInfo();
46 api_collection->usage_page = collection.usage.usage_page;
47 api_collection->usage = collection.usage.usage;
49 api_collection->report_ids.resize(collection.report_ids.size());
50 std::copy(collection.report_ids.begin(), collection.report_ids.end(),
51 api_collection->report_ids.begin());
53 output->collections.push_back(make_linked_ptr(api_collection));
56 const std::vector<uint8>& report_descriptor = input->report_descriptor();
57 if (report_descriptor.size() > 0) {
58 output->report_descriptor.assign(report_descriptor.begin(),
59 report_descriptor.end());
63 bool WillDispatchDeviceEvent(base::WeakPtr<HidDeviceManager> device_manager,
64 scoped_refptr<device::HidDeviceInfo> device_info,
65 content::BrowserContext* context,
66 const Extension* extension,
67 Event* event,
68 const base::DictionaryValue* listener_filter) {
69 if (device_manager && extension) {
70 return device_manager->HasPermission(extension, device_info, false);
72 return false;
75 } // namespace
77 struct HidDeviceManager::GetApiDevicesParams {
78 public:
79 GetApiDevicesParams(const Extension* extension,
80 const std::vector<HidDeviceFilter>& filters,
81 const GetApiDevicesCallback& callback)
82 : extension(extension), filters(filters), callback(callback) {}
83 ~GetApiDevicesParams() {}
85 const Extension* extension;
86 std::vector<HidDeviceFilter> filters;
87 GetApiDevicesCallback callback;
90 HidDeviceManager::HidDeviceManager(content::BrowserContext* context)
91 : browser_context_(context),
92 hid_service_observer_(this),
93 weak_factory_(this) {
94 event_router_ = EventRouter::Get(context);
95 if (event_router_) {
96 event_router_->RegisterObserver(this, hid::OnDeviceAdded::kEventName);
97 event_router_->RegisterObserver(this, hid::OnDeviceRemoved::kEventName);
101 HidDeviceManager::~HidDeviceManager() {
102 DCHECK(thread_checker_.CalledOnValidThread());
105 // static
106 BrowserContextKeyedAPIFactory<HidDeviceManager>*
107 HidDeviceManager::GetFactoryInstance() {
108 static base::LazyInstance<BrowserContextKeyedAPIFactory<HidDeviceManager> >
109 factory = LAZY_INSTANCE_INITIALIZER;
110 return &factory.Get();
113 void HidDeviceManager::GetApiDevices(
114 const Extension* extension,
115 const std::vector<HidDeviceFilter>& filters,
116 const GetApiDevicesCallback& callback) {
117 DCHECK(thread_checker_.CalledOnValidThread());
118 LazyInitialize();
120 if (enumeration_ready_) {
121 scoped_ptr<base::ListValue> devices =
122 CreateApiDeviceList(extension, filters);
123 base::MessageLoop::current()->PostTask(
124 FROM_HERE, base::Bind(callback, base::Passed(&devices)));
125 } else {
126 pending_enumerations_.push_back(
127 new GetApiDevicesParams(extension, filters, callback));
131 scoped_ptr<base::ListValue> HidDeviceManager::GetApiDevicesFromList(
132 const std::vector<scoped_refptr<HidDeviceInfo>>& devices) {
133 DCHECK(thread_checker_.CalledOnValidThread());
134 scoped_ptr<base::ListValue> device_list(new base::ListValue());
135 for (const auto& device : devices) {
136 const auto device_entry = resource_ids_.find(device->device_id());
137 DCHECK(device_entry != resource_ids_.end());
139 hid::HidDeviceInfo device_info;
140 device_info.device_id = device_entry->second;
141 PopulateHidDeviceInfo(&device_info, device);
142 device_list->Append(device_info.ToValue().release());
144 return device_list.Pass();
147 scoped_refptr<HidDeviceInfo> HidDeviceManager::GetDeviceInfo(int resource_id) {
148 DCHECK(thread_checker_.CalledOnValidThread());
149 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
150 DCHECK(hid_service);
152 ResourceIdToDeviceIdMap::const_iterator device_iter =
153 device_ids_.find(resource_id);
154 if (device_iter == device_ids_.end()) {
155 return nullptr;
158 return hid_service->GetDeviceInfo(device_iter->second);
161 bool HidDeviceManager::HasPermission(const Extension* extension,
162 scoped_refptr<HidDeviceInfo> device_info,
163 bool update_last_used) {
164 DevicePermissionsManager* permissions_manager =
165 DevicePermissionsManager::Get(browser_context_);
166 CHECK(permissions_manager);
167 DevicePermissions* device_permissions =
168 permissions_manager->GetForExtension(extension->id());
169 DCHECK(device_permissions);
170 scoped_refptr<DevicePermissionEntry> permission_entry =
171 device_permissions->FindHidDeviceEntry(device_info);
172 if (permission_entry) {
173 if (update_last_used) {
174 permissions_manager->UpdateLastUsed(extension->id(), permission_entry);
176 return true;
179 UsbDevicePermission::CheckParam usbParam(
180 device_info->vendor_id(), device_info->product_id(),
181 UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
182 if (extension->permissions_data()->CheckAPIPermissionWithParam(
183 APIPermission::kUsbDevice, &usbParam)) {
184 return true;
187 if (extension->permissions_data()->HasAPIPermission(
188 APIPermission::kU2fDevices)) {
189 HidDeviceFilter u2f_filter;
190 u2f_filter.SetUsagePage(0xF1D0);
191 if (u2f_filter.Matches(device_info)) {
192 return true;
196 return false;
199 void HidDeviceManager::Shutdown() {
200 if (event_router_) {
201 event_router_->UnregisterObserver(this);
205 void HidDeviceManager::OnListenerAdded(const EventListenerInfo& details) {
206 LazyInitialize();
209 void HidDeviceManager::OnDeviceAdded(scoped_refptr<HidDeviceInfo> device_info) {
210 DCHECK(thread_checker_.CalledOnValidThread());
211 DCHECK_LT(next_resource_id_, std::numeric_limits<int>::max());
212 int new_id = next_resource_id_++;
213 DCHECK(!ContainsKey(resource_ids_, device_info->device_id()));
214 resource_ids_[device_info->device_id()] = new_id;
215 device_ids_[new_id] = device_info->device_id();
217 // Don't generate events during the initial enumeration.
218 if (enumeration_ready_ && event_router_) {
219 api::hid::HidDeviceInfo api_device_info;
220 api_device_info.device_id = new_id;
221 PopulateHidDeviceInfo(&api_device_info, device_info);
223 if (api_device_info.collections.size() > 0) {
224 scoped_ptr<base::ListValue> args(
225 hid::OnDeviceAdded::Create(api_device_info));
226 DispatchEvent(events::HID_ON_DEVICE_ADDED, hid::OnDeviceAdded::kEventName,
227 args.Pass(), device_info);
232 void HidDeviceManager::OnDeviceRemoved(
233 scoped_refptr<HidDeviceInfo> device_info) {
234 DCHECK(thread_checker_.CalledOnValidThread());
235 const auto& resource_entry = resource_ids_.find(device_info->device_id());
236 DCHECK(resource_entry != resource_ids_.end());
237 int resource_id = resource_entry->second;
238 const auto& device_entry = device_ids_.find(resource_id);
239 DCHECK(device_entry != device_ids_.end());
240 resource_ids_.erase(resource_entry);
241 device_ids_.erase(device_entry);
243 if (event_router_) {
244 DCHECK(enumeration_ready_);
245 scoped_ptr<base::ListValue> args(hid::OnDeviceRemoved::Create(resource_id));
246 DispatchEvent(events::HID_ON_DEVICE_REMOVED,
247 hid::OnDeviceRemoved::kEventName, args.Pass(), device_info);
251 void HidDeviceManager::LazyInitialize() {
252 DCHECK(thread_checker_.CalledOnValidThread());
254 if (initialized_) {
255 return;
258 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
259 DCHECK(hid_service);
260 hid_service->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete,
261 weak_factory_.GetWeakPtr()));
263 hid_service_observer_.Add(hid_service);
264 initialized_ = true;
267 scoped_ptr<base::ListValue> HidDeviceManager::CreateApiDeviceList(
268 const Extension* extension,
269 const std::vector<HidDeviceFilter>& filters) {
270 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
271 DCHECK(hid_service);
273 scoped_ptr<base::ListValue> api_devices(new base::ListValue());
274 for (const ResourceIdToDeviceIdMap::value_type& map_entry : device_ids_) {
275 int resource_id = map_entry.first;
276 const HidDeviceId& device_id = map_entry.second;
278 scoped_refptr<HidDeviceInfo> device_info =
279 hid_service->GetDeviceInfo(device_id);
280 if (!device_info) {
281 continue;
284 if (!filters.empty() &&
285 !HidDeviceFilter::MatchesAny(device_info, filters)) {
286 continue;
289 if (!HasPermission(extension, device_info, false)) {
290 continue;
293 hid::HidDeviceInfo api_device_info;
294 api_device_info.device_id = resource_id;
295 PopulateHidDeviceInfo(&api_device_info, device_info);
297 // Expose devices with which user can communicate.
298 if (api_device_info.collections.size() > 0) {
299 api_devices->Append(api_device_info.ToValue());
303 return api_devices.Pass();
306 void HidDeviceManager::OnEnumerationComplete(
307 const std::vector<scoped_refptr<HidDeviceInfo>>& devices) {
308 DCHECK(resource_ids_.empty());
309 DCHECK(device_ids_.empty());
310 for (const scoped_refptr<HidDeviceInfo>& device_info : devices) {
311 OnDeviceAdded(device_info);
313 enumeration_ready_ = true;
315 for (const GetApiDevicesParams* params : pending_enumerations_) {
316 scoped_ptr<base::ListValue> devices =
317 CreateApiDeviceList(params->extension, params->filters);
318 params->callback.Run(devices.Pass());
320 pending_enumerations_.clear();
323 void HidDeviceManager::DispatchEvent(events::HistogramValue histogram_value,
324 const std::string& event_name,
325 scoped_ptr<base::ListValue> event_args,
326 scoped_refptr<HidDeviceInfo> device_info) {
327 scoped_ptr<Event> event(
328 new Event(histogram_value, event_name, event_args.Pass()));
329 event->will_dispatch_callback = base::Bind(
330 &WillDispatchDeviceEvent, weak_factory_.GetWeakPtr(), device_info);
331 event_router_->BroadcastEvent(event.Pass());
334 } // namespace extensions