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/common/permissions/permissions_data.h"
15 #include "extensions/common/permissions/usb_device_permission.h"
17 namespace hid
= extensions::core_api::hid
;
19 using device::HidDeviceFilter
;
20 using device::HidDeviceId
;
21 using device::HidDeviceInfo
;
22 using device::HidService
;
24 namespace extensions
{
28 void PopulateHidDeviceInfo(hid::HidDeviceInfo
* output
,
29 scoped_refptr
<HidDeviceInfo
> input
) {
30 output
->vendor_id
= input
->vendor_id();
31 output
->product_id
= input
->product_id();
32 output
->max_input_report_size
= input
->max_input_report_size();
33 output
->max_output_report_size
= input
->max_output_report_size();
34 output
->max_feature_report_size
= input
->max_feature_report_size();
36 for (const device::HidCollectionInfo
& collection
: input
->collections()) {
37 // Don't expose sensitive data.
38 if (collection
.usage
.IsProtected()) {
42 hid::HidCollectionInfo
* api_collection
= new hid::HidCollectionInfo();
43 api_collection
->usage_page
= collection
.usage
.usage_page
;
44 api_collection
->usage
= collection
.usage
.usage
;
46 api_collection
->report_ids
.resize(collection
.report_ids
.size());
47 std::copy(collection
.report_ids
.begin(), collection
.report_ids
.end(),
48 api_collection
->report_ids
.begin());
50 output
->collections
.push_back(make_linked_ptr(api_collection
));
53 const std::vector
<uint8
>& report_descriptor
= input
->report_descriptor();
54 if (report_descriptor
.size() > 0) {
55 output
->report_descriptor
.assign(report_descriptor
.begin(),
56 report_descriptor
.end());
60 bool WillDispatchDeviceEvent(scoped_refptr
<HidDeviceInfo
> device_info
,
61 content::BrowserContext
* context
,
62 const Extension
* extension
,
63 base::ListValue
* event_args
) {
65 return HidDeviceManager::HasPermission(extension
, device_info
);
72 struct HidDeviceManager::GetApiDevicesParams
{
74 GetApiDevicesParams(const Extension
* extension
,
75 const std::vector
<HidDeviceFilter
>& filters
,
76 const GetApiDevicesCallback
& callback
)
77 : extension(extension
), filters(filters
), callback(callback
) {}
78 ~GetApiDevicesParams() {}
80 const Extension
* extension
;
81 std::vector
<HidDeviceFilter
> filters
;
82 GetApiDevicesCallback callback
;
85 HidDeviceManager::HidDeviceManager(content::BrowserContext
* context
)
86 : initialized_(false),
87 hid_service_observer_(this),
88 enumeration_ready_(false),
91 event_router_
= EventRouter::Get(context
);
93 event_router_
->RegisterObserver(this, hid::OnDeviceAdded::kEventName
);
94 event_router_
->RegisterObserver(this, hid::OnDeviceRemoved::kEventName
);
98 HidDeviceManager::~HidDeviceManager() {
99 DCHECK(thread_checker_
.CalledOnValidThread());
103 BrowserContextKeyedAPIFactory
<HidDeviceManager
>*
104 HidDeviceManager::GetFactoryInstance() {
105 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<HidDeviceManager
> >
106 factory
= LAZY_INSTANCE_INITIALIZER
;
107 return &factory
.Get();
110 void HidDeviceManager::GetApiDevices(
111 const Extension
* extension
,
112 const std::vector
<HidDeviceFilter
>& filters
,
113 const GetApiDevicesCallback
& callback
) {
114 DCHECK(thread_checker_
.CalledOnValidThread());
117 if (enumeration_ready_
) {
118 scoped_ptr
<base::ListValue
> devices
=
119 CreateApiDeviceList(extension
, filters
);
120 base::MessageLoop::current()->PostTask(
121 FROM_HERE
, base::Bind(callback
, base::Passed(&devices
)));
123 pending_enumerations_
.push_back(
124 new GetApiDevicesParams(extension
, filters
, callback
));
128 scoped_refptr
<HidDeviceInfo
> HidDeviceManager::GetDeviceInfo(int resource_id
) {
129 DCHECK(thread_checker_
.CalledOnValidThread());
130 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
133 ResourceIdToDeviceIdMap::const_iterator device_iter
=
134 device_ids_
.find(resource_id
);
135 if (device_iter
== device_ids_
.end()) {
139 return hid_service
->GetDeviceInfo(device_iter
->second
);
143 bool HidDeviceManager::HasPermission(const Extension
* extension
,
144 scoped_refptr
<HidDeviceInfo
> device_info
) {
145 UsbDevicePermission::CheckParam
usbParam(
146 device_info
->vendor_id(), device_info
->product_id(),
147 UsbDevicePermissionData::UNSPECIFIED_INTERFACE
);
148 if (extension
->permissions_data()->CheckAPIPermissionWithParam(
149 APIPermission::kUsbDevice
, &usbParam
)) {
153 if (extension
->permissions_data()->HasAPIPermission(
154 APIPermission::kU2fDevices
)) {
155 HidDeviceFilter u2f_filter
;
156 u2f_filter
.SetUsagePage(0xF1D0);
157 if (u2f_filter
.Matches(device_info
)) {
165 void HidDeviceManager::Shutdown() {
167 event_router_
->UnregisterObserver(this);
171 void HidDeviceManager::OnListenerAdded(const EventListenerInfo
& details
) {
175 void HidDeviceManager::OnDeviceAdded(scoped_refptr
<HidDeviceInfo
> device_info
) {
176 DCHECK(thread_checker_
.CalledOnValidThread());
177 DCHECK_LT(next_resource_id_
, std::numeric_limits
<int>::max());
178 int new_id
= next_resource_id_
++;
179 DCHECK(!ContainsKey(resource_ids_
, device_info
->device_id()));
180 resource_ids_
[device_info
->device_id()] = new_id
;
181 device_ids_
[new_id
] = device_info
->device_id();
183 // Don't generate events during the initial enumeration.
184 if (enumeration_ready_
&& event_router_
) {
185 core_api::hid::HidDeviceInfo api_device_info
;
186 api_device_info
.device_id
= new_id
;
187 PopulateHidDeviceInfo(&api_device_info
, device_info
);
189 if (api_device_info
.collections
.size() > 0) {
190 scoped_ptr
<base::ListValue
> args(
191 hid::OnDeviceAdded::Create(api_device_info
));
192 DispatchEvent(hid::OnDeviceAdded::kEventName
, args
.Pass(), device_info
);
197 void HidDeviceManager::OnDeviceRemoved(
198 scoped_refptr
<HidDeviceInfo
> device_info
) {
199 DCHECK(thread_checker_
.CalledOnValidThread());
200 const auto& resource_entry
= resource_ids_
.find(device_info
->device_id());
201 DCHECK(resource_entry
!= resource_ids_
.end());
202 int resource_id
= resource_entry
->second
;
203 const auto& device_entry
= device_ids_
.find(resource_id
);
204 DCHECK(device_entry
!= device_ids_
.end());
205 resource_ids_
.erase(resource_entry
);
206 device_ids_
.erase(device_entry
);
209 DCHECK(enumeration_ready_
);
210 scoped_ptr
<base::ListValue
> args(hid::OnDeviceRemoved::Create(resource_id
));
211 DispatchEvent(hid::OnDeviceRemoved::kEventName
, args
.Pass(), device_info
);
215 void HidDeviceManager::LazyInitialize() {
216 DCHECK(thread_checker_
.CalledOnValidThread());
222 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
224 hid_service
->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete
,
225 weak_factory_
.GetWeakPtr()));
227 hid_service_observer_
.Add(hid_service
);
231 scoped_ptr
<base::ListValue
> HidDeviceManager::CreateApiDeviceList(
232 const Extension
* extension
,
233 const std::vector
<HidDeviceFilter
>& filters
) {
234 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
237 scoped_ptr
<base::ListValue
> api_devices(new base::ListValue());
238 for (const ResourceIdToDeviceIdMap::value_type
& map_entry
: device_ids_
) {
239 int resource_id
= map_entry
.first
;
240 const HidDeviceId
& device_id
= map_entry
.second
;
242 scoped_refptr
<HidDeviceInfo
> device_info
=
243 hid_service
->GetDeviceInfo(device_id
);
248 if (!filters
.empty() &&
249 !HidDeviceFilter::MatchesAny(device_info
, filters
)) {
253 if (!HasPermission(extension
, device_info
)) {
257 hid::HidDeviceInfo api_device_info
;
258 api_device_info
.device_id
= resource_id
;
259 PopulateHidDeviceInfo(&api_device_info
, device_info
);
261 // Expose devices with which user can communicate.
262 if (api_device_info
.collections
.size() > 0) {
263 api_devices
->Append(api_device_info
.ToValue().release());
267 return api_devices
.Pass();
270 void HidDeviceManager::OnEnumerationComplete(
271 const std::vector
<scoped_refptr
<HidDeviceInfo
>>& devices
) {
272 DCHECK(resource_ids_
.empty());
273 DCHECK(device_ids_
.empty());
274 for (const scoped_refptr
<HidDeviceInfo
>& device_info
: devices
) {
275 OnDeviceAdded(device_info
);
277 enumeration_ready_
= true;
279 for (const GetApiDevicesParams
* params
: pending_enumerations_
) {
280 scoped_ptr
<base::ListValue
> devices
=
281 CreateApiDeviceList(params
->extension
, params
->filters
);
282 params
->callback
.Run(devices
.Pass());
284 pending_enumerations_
.clear();
287 void HidDeviceManager::DispatchEvent(const std::string
& event_name
,
288 scoped_ptr
<base::ListValue
> event_args
,
289 scoped_refptr
<HidDeviceInfo
> device_info
) {
290 scoped_ptr
<Event
> event(new Event(event_name
, event_args
.Pass()));
291 event
->will_dispatch_callback
=
292 base::Bind(&WillDispatchDeviceEvent
, device_info
);
293 event_router_
->BroadcastEvent(event
.Pass());
296 } // namespace extensions