Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_device_manager.cc
blob5a6403c87c95b01bc5fb318e76adb27b5c647ee1
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/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 {
26 namespace {
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()) {
39 continue;
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) {
64 if (extension) {
65 return HidDeviceManager::HasPermission(extension, device_info);
67 return false;
70 } // namespace
72 struct HidDeviceManager::GetApiDevicesParams {
73 public:
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),
89 next_resource_id_(0),
90 weak_factory_(this) {
91 event_router_ = EventRouter::Get(context);
92 if (event_router_) {
93 event_router_->RegisterObserver(this, hid::OnDeviceAdded::kEventName);
94 event_router_->RegisterObserver(this, hid::OnDeviceRemoved::kEventName);
98 HidDeviceManager::~HidDeviceManager() {
99 DCHECK(thread_checker_.CalledOnValidThread());
102 // static
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());
115 LazyInitialize();
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)));
122 } else {
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();
131 DCHECK(hid_service);
133 ResourceIdToDeviceIdMap::const_iterator device_iter =
134 device_ids_.find(resource_id);
135 if (device_iter == device_ids_.end()) {
136 return nullptr;
139 return hid_service->GetDeviceInfo(device_iter->second);
142 // static
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)) {
150 return true;
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)) {
158 return true;
162 return false;
165 void HidDeviceManager::Shutdown() {
166 if (event_router_) {
167 event_router_->UnregisterObserver(this);
171 void HidDeviceManager::OnListenerAdded(const EventListenerInfo& details) {
172 LazyInitialize();
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);
208 if (event_router_) {
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());
218 if (initialized_) {
219 return;
222 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
223 DCHECK(hid_service);
224 hid_service->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete,
225 weak_factory_.GetWeakPtr()));
227 hid_service_observer_.Add(hid_service);
228 initialized_ = true;
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();
235 DCHECK(hid_service);
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);
244 if (!device_info) {
245 continue;
248 if (!filters.empty() &&
249 !HidDeviceFilter::MatchesAny(device_info, filters)) {
250 continue;
253 if (!HasPermission(extension, device_info)) {
254 continue;
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