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"
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
{
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()) {
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
,
68 const base::DictionaryValue
* listener_filter
) {
69 if (device_manager
&& extension
) {
70 return device_manager
->HasPermission(extension
, device_info
, false);
77 struct HidDeviceManager::GetApiDevicesParams
{
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),
94 event_router_
= EventRouter::Get(context
);
96 event_router_
->RegisterObserver(this, hid::OnDeviceAdded::kEventName
);
97 event_router_
->RegisterObserver(this, hid::OnDeviceRemoved::kEventName
);
101 HidDeviceManager::~HidDeviceManager() {
102 DCHECK(thread_checker_
.CalledOnValidThread());
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());
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
)));
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();
152 ResourceIdToDeviceIdMap::const_iterator device_iter
=
153 device_ids_
.find(resource_id
);
154 if (device_iter
== device_ids_
.end()) {
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
);
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
)) {
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
)) {
199 void HidDeviceManager::Shutdown() {
201 event_router_
->UnregisterObserver(this);
205 void HidDeviceManager::OnListenerAdded(const EventListenerInfo
& details
) {
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
);
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());
258 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
260 hid_service
->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete
,
261 weak_factory_
.GetWeakPtr()));
263 hid_service_observer_
.Add(hid_service
);
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();
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
);
284 if (!filters
.empty() &&
285 !HidDeviceFilter::MatchesAny(device_info
, filters
)) {
289 if (!HasPermission(extension
, device_info
, false)) {
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