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
<HidDeviceInfo
> input
) {
31 output
->vendor_id
= input
->vendor_id();
32 output
->product_id
= input
->product_id();
33 output
->max_input_report_size
= input
->max_input_report_size();
34 output
->max_output_report_size
= input
->max_output_report_size();
35 output
->max_feature_report_size
= input
->max_feature_report_size();
37 for (const device::HidCollectionInfo
& collection
: input
->collections()) {
38 // Don't expose sensitive data.
39 if (collection
.usage
.IsProtected()) {
43 hid::HidCollectionInfo
* api_collection
= new hid::HidCollectionInfo();
44 api_collection
->usage_page
= collection
.usage
.usage_page
;
45 api_collection
->usage
= collection
.usage
.usage
;
47 api_collection
->report_ids
.resize(collection
.report_ids
.size());
48 std::copy(collection
.report_ids
.begin(), collection
.report_ids
.end(),
49 api_collection
->report_ids
.begin());
51 output
->collections
.push_back(make_linked_ptr(api_collection
));
54 const std::vector
<uint8
>& report_descriptor
= input
->report_descriptor();
55 if (report_descriptor
.size() > 0) {
56 output
->report_descriptor
.assign(report_descriptor
.begin(),
57 report_descriptor
.end());
61 bool WillDispatchDeviceEvent(base::WeakPtr
<HidDeviceManager
> device_manager
,
62 scoped_refptr
<device::HidDeviceInfo
> device_info
,
63 content::BrowserContext
* context
,
64 const Extension
* extension
,
65 base::ListValue
* event_args
,
66 const base::DictionaryValue
* listener_filter
) {
67 if (device_manager
&& extension
) {
68 return device_manager
->HasPermission(extension
, device_info
, false);
75 struct HidDeviceManager::GetApiDevicesParams
{
77 GetApiDevicesParams(const Extension
* extension
,
78 const std::vector
<HidDeviceFilter
>& filters
,
79 const GetApiDevicesCallback
& callback
)
80 : extension(extension
), filters(filters
), callback(callback
) {}
81 ~GetApiDevicesParams() {}
83 const Extension
* extension
;
84 std::vector
<HidDeviceFilter
> filters
;
85 GetApiDevicesCallback callback
;
88 HidDeviceManager::HidDeviceManager(content::BrowserContext
* context
)
89 : browser_context_(context
),
90 hid_service_observer_(this),
92 event_router_
= EventRouter::Get(context
);
94 event_router_
->RegisterObserver(this, hid::OnDeviceAdded::kEventName
);
95 event_router_
->RegisterObserver(this, hid::OnDeviceRemoved::kEventName
);
99 HidDeviceManager::~HidDeviceManager() {
100 DCHECK(thread_checker_
.CalledOnValidThread());
104 BrowserContextKeyedAPIFactory
<HidDeviceManager
>*
105 HidDeviceManager::GetFactoryInstance() {
106 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<HidDeviceManager
> >
107 factory
= LAZY_INSTANCE_INITIALIZER
;
108 return &factory
.Get();
111 void HidDeviceManager::GetApiDevices(
112 const Extension
* extension
,
113 const std::vector
<HidDeviceFilter
>& filters
,
114 const GetApiDevicesCallback
& callback
) {
115 DCHECK(thread_checker_
.CalledOnValidThread());
118 if (enumeration_ready_
) {
119 scoped_ptr
<base::ListValue
> devices
=
120 CreateApiDeviceList(extension
, filters
);
121 base::MessageLoop::current()->PostTask(
122 FROM_HERE
, base::Bind(callback
, base::Passed(&devices
)));
124 pending_enumerations_
.push_back(
125 new GetApiDevicesParams(extension
, filters
, callback
));
129 scoped_ptr
<base::ListValue
> HidDeviceManager::GetApiDevicesFromList(
130 const std::vector
<scoped_refptr
<HidDeviceInfo
>>& devices
) {
131 DCHECK(thread_checker_
.CalledOnValidThread());
132 scoped_ptr
<base::ListValue
> device_list(new base::ListValue());
133 for (const auto& device
: devices
) {
134 const auto device_entry
= resource_ids_
.find(device
->device_id());
135 DCHECK(device_entry
!= resource_ids_
.end());
137 hid::HidDeviceInfo device_info
;
138 device_info
.device_id
= device_entry
->second
;
139 PopulateHidDeviceInfo(&device_info
, device
);
140 device_list
->Append(device_info
.ToValue().release());
142 return device_list
.Pass();
145 scoped_refptr
<HidDeviceInfo
> HidDeviceManager::GetDeviceInfo(int resource_id
) {
146 DCHECK(thread_checker_
.CalledOnValidThread());
147 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
150 ResourceIdToDeviceIdMap::const_iterator device_iter
=
151 device_ids_
.find(resource_id
);
152 if (device_iter
== device_ids_
.end()) {
156 return hid_service
->GetDeviceInfo(device_iter
->second
);
159 bool HidDeviceManager::HasPermission(const Extension
* extension
,
160 scoped_refptr
<HidDeviceInfo
> device_info
,
161 bool update_last_used
) {
162 DevicePermissionsManager
* permissions_manager
=
163 DevicePermissionsManager::Get(browser_context_
);
164 CHECK(permissions_manager
);
165 DevicePermissions
* device_permissions
=
166 permissions_manager
->GetForExtension(extension
->id());
167 DCHECK(device_permissions
);
168 scoped_refptr
<DevicePermissionEntry
> permission_entry
=
169 device_permissions
->FindHidDeviceEntry(device_info
);
170 if (permission_entry
) {
171 if (update_last_used
) {
172 permissions_manager
->UpdateLastUsed(extension
->id(), permission_entry
);
177 UsbDevicePermission::CheckParam
usbParam(
178 device_info
->vendor_id(), device_info
->product_id(),
179 UsbDevicePermissionData::UNSPECIFIED_INTERFACE
);
180 if (extension
->permissions_data()->CheckAPIPermissionWithParam(
181 APIPermission::kUsbDevice
, &usbParam
)) {
185 if (extension
->permissions_data()->HasAPIPermission(
186 APIPermission::kU2fDevices
)) {
187 HidDeviceFilter u2f_filter
;
188 u2f_filter
.SetUsagePage(0xF1D0);
189 if (u2f_filter
.Matches(device_info
)) {
197 void HidDeviceManager::Shutdown() {
199 event_router_
->UnregisterObserver(this);
203 void HidDeviceManager::OnListenerAdded(const EventListenerInfo
& details
) {
207 void HidDeviceManager::OnDeviceAdded(scoped_refptr
<HidDeviceInfo
> device_info
) {
208 DCHECK(thread_checker_
.CalledOnValidThread());
209 DCHECK_LT(next_resource_id_
, std::numeric_limits
<int>::max());
210 int new_id
= next_resource_id_
++;
211 DCHECK(!ContainsKey(resource_ids_
, device_info
->device_id()));
212 resource_ids_
[device_info
->device_id()] = new_id
;
213 device_ids_
[new_id
] = device_info
->device_id();
215 // Don't generate events during the initial enumeration.
216 if (enumeration_ready_
&& event_router_
) {
217 api::hid::HidDeviceInfo api_device_info
;
218 api_device_info
.device_id
= new_id
;
219 PopulateHidDeviceInfo(&api_device_info
, device_info
);
221 if (api_device_info
.collections
.size() > 0) {
222 scoped_ptr
<base::ListValue
> args(
223 hid::OnDeviceAdded::Create(api_device_info
));
224 DispatchEvent(events::HID_ON_DEVICE_ADDED
, hid::OnDeviceAdded::kEventName
,
225 args
.Pass(), device_info
);
230 void HidDeviceManager::OnDeviceRemoved(
231 scoped_refptr
<HidDeviceInfo
> device_info
) {
232 DCHECK(thread_checker_
.CalledOnValidThread());
233 const auto& resource_entry
= resource_ids_
.find(device_info
->device_id());
234 DCHECK(resource_entry
!= resource_ids_
.end());
235 int resource_id
= resource_entry
->second
;
236 const auto& device_entry
= device_ids_
.find(resource_id
);
237 DCHECK(device_entry
!= device_ids_
.end());
238 resource_ids_
.erase(resource_entry
);
239 device_ids_
.erase(device_entry
);
242 DCHECK(enumeration_ready_
);
243 scoped_ptr
<base::ListValue
> args(hid::OnDeviceRemoved::Create(resource_id
));
244 DispatchEvent(events::HID_ON_DEVICE_REMOVED
,
245 hid::OnDeviceRemoved::kEventName
, args
.Pass(), device_info
);
249 void HidDeviceManager::LazyInitialize() {
250 DCHECK(thread_checker_
.CalledOnValidThread());
256 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
258 hid_service
->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete
,
259 weak_factory_
.GetWeakPtr()));
261 hid_service_observer_
.Add(hid_service
);
265 scoped_ptr
<base::ListValue
> HidDeviceManager::CreateApiDeviceList(
266 const Extension
* extension
,
267 const std::vector
<HidDeviceFilter
>& filters
) {
268 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
271 scoped_ptr
<base::ListValue
> api_devices(new base::ListValue());
272 for (const ResourceIdToDeviceIdMap::value_type
& map_entry
: device_ids_
) {
273 int resource_id
= map_entry
.first
;
274 const HidDeviceId
& device_id
= map_entry
.second
;
276 scoped_refptr
<HidDeviceInfo
> device_info
=
277 hid_service
->GetDeviceInfo(device_id
);
282 if (!filters
.empty() &&
283 !HidDeviceFilter::MatchesAny(device_info
, filters
)) {
287 if (!HasPermission(extension
, device_info
, false)) {
291 hid::HidDeviceInfo api_device_info
;
292 api_device_info
.device_id
= resource_id
;
293 PopulateHidDeviceInfo(&api_device_info
, device_info
);
295 // Expose devices with which user can communicate.
296 if (api_device_info
.collections
.size() > 0) {
297 api_devices
->Append(api_device_info
.ToValue().release());
301 return api_devices
.Pass();
304 void HidDeviceManager::OnEnumerationComplete(
305 const std::vector
<scoped_refptr
<HidDeviceInfo
>>& devices
) {
306 DCHECK(resource_ids_
.empty());
307 DCHECK(device_ids_
.empty());
308 for (const scoped_refptr
<HidDeviceInfo
>& device_info
: devices
) {
309 OnDeviceAdded(device_info
);
311 enumeration_ready_
= true;
313 for (const GetApiDevicesParams
* params
: pending_enumerations_
) {
314 scoped_ptr
<base::ListValue
> devices
=
315 CreateApiDeviceList(params
->extension
, params
->filters
);
316 params
->callback
.Run(devices
.Pass());
318 pending_enumerations_
.clear();
321 void HidDeviceManager::DispatchEvent(events::HistogramValue histogram_value
,
322 const std::string
& event_name
,
323 scoped_ptr
<base::ListValue
> event_args
,
324 scoped_refptr
<HidDeviceInfo
> device_info
) {
325 scoped_ptr
<Event
> event(
326 new Event(histogram_value
, event_name
, event_args
.Pass()));
327 event
->will_dispatch_callback
= base::Bind(
328 &WillDispatchDeviceEvent
, weak_factory_
.GetWeakPtr(), device_info
);
329 event_router_
->BroadcastEvent(event
.Pass());
332 } // namespace extensions