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/device_permissions_manager.h"
8 #include "base/memory/singleton.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "components/keyed_service/content/browser_context_dependency_manager.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "device/core/device_client.h"
16 #include "device/hid/hid_device_info.h"
17 #include "device/hid/hid_service.h"
18 #include "device/usb/usb_device.h"
19 #include "device/usb/usb_ids.h"
20 #include "extensions/browser/extension_host.h"
21 #include "extensions/browser/extension_prefs.h"
22 #include "extensions/browser/extensions_browser_client.h"
23 #include "extensions/common/value_builder.h"
24 #include "extensions/strings/grit/extensions_strings.h"
25 #include "ui/base/l10n/l10n_util.h"
27 namespace extensions
{
29 using content::BrowserContext
;
30 using content::BrowserThread
;
31 using device::HidDeviceInfo
;
32 using device::HidService
;
33 using device::UsbDevice
;
34 using device::UsbService
;
35 using extensions::APIPermission
;
36 using extensions::Extension
;
37 using extensions::ExtensionHost
;
38 using extensions::ExtensionPrefs
;
44 // The device that the app has permission to access.
45 const char kDevices
[] = "devices";
47 // The type of device saved.
48 const char kDeviceType
[] = "type";
50 // Type identifier for USB devices.
51 const char kDeviceTypeUsb
[] = "usb";
53 // Type identifier for HID devices.
54 const char kDeviceTypeHid
[] = "hid";
56 // The vendor ID of the device that the app had permission to access.
57 const char kDeviceVendorId
[] = "vendor_id";
59 // The product ID of the device that the app had permission to access.
60 const char kDeviceProductId
[] = "product_id";
62 // The serial number of the device that the app has permission to access.
63 const char kDeviceSerialNumber
[] = "serial_number";
65 // The manufacturer string read from the device that the app has permission to
67 const char kDeviceManufacturerString
[] = "manufacturer_string";
69 // The product string read from the device that the app has permission to
71 const char kDeviceProductString
[] = "product_string";
73 // Serialized timestamp of the last time when the device was opened by the app.
74 const char kDeviceLastUsed
[] = "last_used_time";
76 // Converts a DevicePermissionEntry::Type to a string for the prefs file.
77 const char* TypeToString(DevicePermissionEntry::Type type
) {
79 case DevicePermissionEntry::Type::USB
:
80 return kDeviceTypeUsb
;
81 case DevicePermissionEntry::Type::HID
:
82 return kDeviceTypeHid
;
88 // Persists a DevicePermissionEntry in ExtensionPrefs.
89 void SaveDevicePermissionEntry(BrowserContext
* context
,
90 const std::string
& extension_id
,
91 scoped_refptr
<DevicePermissionEntry
> entry
) {
92 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(context
);
93 ExtensionPrefs::ScopedListUpdate
update(prefs
, extension_id
, kDevices
);
94 base::ListValue
* devices
= update
.Get();
96 devices
= update
.Create();
99 scoped_ptr
<base::Value
> device_entry(entry
->ToValue());
100 DCHECK(devices
->Find(*device_entry
.get()) == devices
->end());
101 devices
->Append(device_entry
.release());
104 bool MatchesDevicePermissionEntry(const base::DictionaryValue
* value
,
105 scoped_refptr
<DevicePermissionEntry
> entry
) {
107 if (!value
->GetStringWithoutPathExpansion(kDeviceType
, &type
) ||
108 type
!= TypeToString(entry
->type())) {
112 if (!value
->GetIntegerWithoutPathExpansion(kDeviceVendorId
, &vendor_id
) ||
113 vendor_id
!= entry
->vendor_id()) {
117 if (!value
->GetIntegerWithoutPathExpansion(kDeviceProductId
, &product_id
) ||
118 product_id
!= entry
->product_id()) {
121 base::string16 serial_number
;
122 if (!value
->GetStringWithoutPathExpansion(kDeviceSerialNumber
,
124 serial_number
!= entry
->serial_number()) {
130 // Updates the timestamp stored in ExtensionPrefs for the given
131 // DevicePermissionEntry.
132 void UpdateDevicePermissionEntry(BrowserContext
* context
,
133 const std::string
& extension_id
,
134 scoped_refptr
<DevicePermissionEntry
> entry
) {
135 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(context
);
136 ExtensionPrefs::ScopedListUpdate
update(prefs
, extension_id
, kDevices
);
137 base::ListValue
* devices
= update
.Get();
142 for (size_t i
= 0; i
< devices
->GetSize(); ++i
) {
143 base::DictionaryValue
* dict_value
;
144 if (!devices
->GetDictionary(i
, &dict_value
)) {
147 if (!MatchesDevicePermissionEntry(dict_value
, entry
)) {
150 devices
->Set(i
, entry
->ToValue().release());
155 // Removes the given DevicePermissionEntry from ExtensionPrefs.
156 void RemoveDevicePermissionEntry(BrowserContext
* context
,
157 const std::string
& extension_id
,
158 scoped_refptr
<DevicePermissionEntry
> entry
) {
159 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(context
);
160 ExtensionPrefs::ScopedListUpdate
update(prefs
, extension_id
, kDevices
);
161 base::ListValue
* devices
= update
.Get();
166 for (size_t i
= 0; i
< devices
->GetSize(); ++i
) {
167 base::DictionaryValue
* dict_value
;
168 if (!devices
->GetDictionary(i
, &dict_value
)) {
171 if (!MatchesDevicePermissionEntry(dict_value
, entry
)) {
174 devices
->Remove(i
, nullptr);
179 // Clears all DevicePermissionEntries for the app from ExtensionPrefs.
180 void ClearDevicePermissionEntries(ExtensionPrefs
* prefs
,
181 const std::string
& extension_id
) {
182 prefs
->UpdateExtensionPref(extension_id
, kDevices
, NULL
);
185 scoped_refptr
<DevicePermissionEntry
> ReadDevicePermissionEntry(
186 const base::DictionaryValue
* entry
) {
188 if (!entry
->GetIntegerWithoutPathExpansion(kDeviceVendorId
, &vendor_id
) ||
189 vendor_id
< 0 || vendor_id
> UINT16_MAX
) {
194 if (!entry
->GetIntegerWithoutPathExpansion(kDeviceProductId
, &product_id
) ||
195 product_id
< 0 || product_id
> UINT16_MAX
) {
199 base::string16 serial_number
;
200 if (!entry
->GetStringWithoutPathExpansion(kDeviceSerialNumber
,
205 base::string16 manufacturer_string
;
206 // Ignore failure as this string is optional.
207 entry
->GetStringWithoutPathExpansion(kDeviceManufacturerString
,
208 &manufacturer_string
);
210 base::string16 product_string
;
211 // Ignore failure as this string is optional.
212 entry
->GetStringWithoutPathExpansion(kDeviceProductString
, &product_string
);
214 // If a last used time is not stored in ExtensionPrefs last_used.is_null()
216 std::string last_used_str
;
217 int64 last_used_i64
= 0;
218 base::Time last_used
;
219 if (entry
->GetStringWithoutPathExpansion(kDeviceLastUsed
, &last_used_str
) &&
220 base::StringToInt64(last_used_str
, &last_used_i64
)) {
221 last_used
= base::Time::FromInternalValue(last_used_i64
);
225 if (!entry
->GetStringWithoutPathExpansion(kDeviceType
, &type
)) {
229 if (type
== kDeviceTypeUsb
) {
230 return new DevicePermissionEntry(
231 DevicePermissionEntry::Type::USB
, vendor_id
, product_id
, serial_number
,
232 manufacturer_string
, product_string
, last_used
);
233 } else if (type
== kDeviceTypeHid
) {
234 return new DevicePermissionEntry(
235 DevicePermissionEntry::Type::HID
, vendor_id
, product_id
, serial_number
,
236 base::string16(), product_string
, last_used
);
241 // Returns all DevicePermissionEntries for the app.
242 std::set
<scoped_refptr
<DevicePermissionEntry
>> GetDevicePermissionEntries(
243 ExtensionPrefs
* prefs
,
244 const std::string
& extension_id
) {
245 std::set
<scoped_refptr
<DevicePermissionEntry
>> result
;
246 const base::ListValue
* devices
= NULL
;
247 if (!prefs
->ReadPrefAsList(extension_id
, kDevices
, &devices
)) {
251 for (const base::Value
* entry
: *devices
) {
252 const base::DictionaryValue
* entry_dict
;
253 if (entry
->GetAsDictionary(&entry_dict
)) {
254 scoped_refptr
<DevicePermissionEntry
> device_entry
=
255 ReadDevicePermissionEntry(entry_dict
);
257 result
.insert(device_entry
);
266 DevicePermissionEntry::DevicePermissionEntry(scoped_refptr
<UsbDevice
> device
)
267 : usb_device_(device
),
269 vendor_id_(device
->vendor_id()),
270 product_id_(device
->product_id()),
271 serial_number_(device
->serial_number()),
272 manufacturer_string_(device
->manufacturer_string()),
273 product_string_(device
->product_string()) {
276 DevicePermissionEntry::DevicePermissionEntry(
277 scoped_refptr
<HidDeviceInfo
> device
)
278 : hid_device_(device
),
280 vendor_id_(device
->vendor_id()),
281 product_id_(device
->product_id()),
282 serial_number_(base::UTF8ToUTF16(device
->serial_number())),
283 product_string_(base::UTF8ToUTF16(device
->product_name())) {
286 DevicePermissionEntry::DevicePermissionEntry(
290 const base::string16
& serial_number
,
291 const base::string16
& manufacturer_string
,
292 const base::string16
& product_string
,
293 const base::Time
& last_used
)
295 vendor_id_(vendor_id
),
296 product_id_(product_id
),
297 serial_number_(serial_number
),
298 manufacturer_string_(manufacturer_string
),
299 product_string_(product_string
),
300 last_used_(last_used
) {
303 DevicePermissionEntry::~DevicePermissionEntry() {
306 bool DevicePermissionEntry::IsPersistent() const {
307 return !serial_number_
.empty();
310 scoped_ptr
<base::Value
> DevicePermissionEntry::ToValue() const {
311 if (!IsPersistent()) {
315 DCHECK(!serial_number_
.empty());
316 scoped_ptr
<base::DictionaryValue
> entry_dict(
318 .Set(kDeviceType
, TypeToString(type_
))
319 .Set(kDeviceVendorId
, vendor_id_
)
320 .Set(kDeviceProductId
, product_id_
)
321 .Set(kDeviceSerialNumber
, serial_number_
)
324 if (!manufacturer_string_
.empty()) {
325 entry_dict
->SetStringWithoutPathExpansion(kDeviceManufacturerString
,
326 manufacturer_string_
);
328 if (!product_string_
.empty()) {
329 entry_dict
->SetStringWithoutPathExpansion(kDeviceProductString
,
332 if (!last_used_
.is_null()) {
333 entry_dict
->SetStringWithoutPathExpansion(
334 kDeviceLastUsed
, base::Int64ToString(last_used_
.ToInternalValue()));
337 return entry_dict
.Pass();
340 base::string16
DevicePermissionEntry::GetPermissionMessageString() const {
341 return DevicePermissionsManager::GetPermissionMessage(
342 vendor_id_
, product_id_
, manufacturer_string_
, product_string_
,
343 serial_number_
, type_
== Type::USB
);
346 DevicePermissions::~DevicePermissions() {
349 scoped_refptr
<DevicePermissionEntry
> DevicePermissions::FindUsbDeviceEntry(
350 scoped_refptr
<UsbDevice
> device
) const {
351 const auto& ephemeral_device_entry
=
352 ephemeral_usb_devices_
.find(device
.get());
353 if (ephemeral_device_entry
!= ephemeral_usb_devices_
.end()) {
354 return ephemeral_device_entry
->second
;
357 if (device
->serial_number().empty()) {
361 for (const auto& entry
: entries_
) {
362 if (entry
->IsPersistent() && entry
->vendor_id() == device
->vendor_id() &&
363 entry
->product_id() == device
->product_id() &&
364 entry
->serial_number() == device
->serial_number()) {
371 scoped_refptr
<DevicePermissionEntry
> DevicePermissions::FindHidDeviceEntry(
372 scoped_refptr
<HidDeviceInfo
> device
) const {
373 const auto& ephemeral_device_entry
=
374 ephemeral_hid_devices_
.find(device
.get());
375 if (ephemeral_device_entry
!= ephemeral_hid_devices_
.end()) {
376 return ephemeral_device_entry
->second
;
379 if (device
->serial_number().empty()) {
383 base::string16 serial_number
= base::UTF8ToUTF16(device
->serial_number());
384 for (const auto& entry
: entries_
) {
385 if (entry
->IsPersistent() && entry
->vendor_id() == device
->vendor_id() &&
386 entry
->product_id() == device
->product_id() &&
387 entry
->serial_number() == serial_number
) {
394 DevicePermissions::DevicePermissions(BrowserContext
* context
,
395 const std::string
& extension_id
) {
396 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(context
);
397 entries_
= GetDevicePermissionEntries(prefs
, extension_id
);
401 DevicePermissionsManager
* DevicePermissionsManager::Get(
402 BrowserContext
* context
) {
403 return DevicePermissionsManagerFactory::GetForBrowserContext(context
);
407 base::string16
DevicePermissionsManager::GetPermissionMessage(
410 const base::string16
& manufacturer_string
,
411 const base::string16
& product_string
,
412 const base::string16
& serial_number
,
413 bool always_include_manufacturer
) {
414 base::string16 product
= product_string
;
415 if (product
.empty()) {
416 const char* product_name
=
417 device::UsbIds::GetProductName(vendor_id
, product_id
);
419 product
= base::UTF8ToUTF16(product_name
);
423 base::string16 manufacturer
= manufacturer_string
;
424 if (manufacturer_string
.empty()) {
425 const char* vendor_name
= device::UsbIds::GetVendorName(vendor_id
);
427 manufacturer
= base::UTF8ToUTF16(vendor_name
);
431 if (serial_number
.empty()) {
432 if (product
.empty()) {
433 product
= base::ASCIIToUTF16(base::StringPrintf("%04x", product_id
));
434 if (manufacturer
.empty()) {
436 base::ASCIIToUTF16(base::StringPrintf("%04x", vendor_id
));
437 return l10n_util::GetStringFUTF16(
438 IDS_DEVICE_NAME_WITH_UNKNOWN_PRODUCT_UNKNOWN_VENDOR
, product
,
441 return l10n_util::GetStringFUTF16(
442 IDS_DEVICE_NAME_WITH_UNKNOWN_PRODUCT_VENDOR
, product
, manufacturer
);
445 if (always_include_manufacturer
) {
446 if (manufacturer
.empty()) {
448 base::ASCIIToUTF16(base::StringPrintf("%04x", vendor_id
));
449 return l10n_util::GetStringFUTF16(
450 IDS_DEVICE_NAME_WITH_PRODUCT_UNKNOWN_VENDOR
, product
,
453 return l10n_util::GetStringFUTF16(IDS_DEVICE_NAME_WITH_PRODUCT_VENDOR
,
454 product
, manufacturer
);
461 if (product
.empty()) {
462 product
= base::ASCIIToUTF16(base::StringPrintf("%04x", product_id
));
463 if (manufacturer
.empty()) {
465 base::ASCIIToUTF16(base::StringPrintf("%04x", vendor_id
));
466 return l10n_util::GetStringFUTF16(
467 IDS_DEVICE_NAME_WITH_UNKNOWN_PRODUCT_UNKNOWN_VENDOR_SERIAL
, product
,
468 manufacturer
, serial_number
);
470 return l10n_util::GetStringFUTF16(
471 IDS_DEVICE_NAME_WITH_UNKNOWN_PRODUCT_VENDOR_SERIAL
, product
,
472 manufacturer
, serial_number
);
475 if (always_include_manufacturer
) {
476 if (manufacturer
.empty()) {
478 base::ASCIIToUTF16(base::StringPrintf("%04x", vendor_id
));
479 return l10n_util::GetStringFUTF16(
480 IDS_DEVICE_NAME_WITH_PRODUCT_UNKNOWN_VENDOR_SERIAL
, product
,
481 manufacturer
, serial_number
);
483 return l10n_util::GetStringFUTF16(
484 IDS_DEVICE_NAME_WITH_PRODUCT_VENDOR_SERIAL
, product
, manufacturer
,
488 return l10n_util::GetStringFUTF16(IDS_DEVICE_NAME_WITH_PRODUCT_SERIAL
,
489 product
, serial_number
);
495 DevicePermissions
* DevicePermissionsManager::GetForExtension(
496 const std::string
& extension_id
) {
497 DCHECK(thread_checker_
.CalledOnValidThread());
498 DevicePermissions
* device_permissions
= GetInternal(extension_id
);
499 if (!device_permissions
) {
500 device_permissions
= new DevicePermissions(context_
, extension_id
);
501 extension_id_to_device_permissions_
[extension_id
] = device_permissions
;
504 return device_permissions
;
507 std::vector
<base::string16
>
508 DevicePermissionsManager::GetPermissionMessageStrings(
509 const std::string
& extension_id
) const {
510 DCHECK(thread_checker_
.CalledOnValidThread());
511 std::vector
<base::string16
> messages
;
512 const DevicePermissions
* device_permissions
= GetInternal(extension_id
);
513 if (device_permissions
) {
514 for (const scoped_refptr
<DevicePermissionEntry
>& entry
:
515 device_permissions
->entries()) {
516 messages
.push_back(entry
->GetPermissionMessageString());
522 void DevicePermissionsManager::AllowUsbDevice(const std::string
& extension_id
,
523 scoped_refptr
<UsbDevice
> device
) {
524 DCHECK(thread_checker_
.CalledOnValidThread());
525 DevicePermissions
* device_permissions
= GetForExtension(extension_id
);
527 scoped_refptr
<DevicePermissionEntry
> device_entry(
528 new DevicePermissionEntry(device
));
530 if (device_entry
->IsPersistent()) {
531 for (const auto& entry
: device_permissions
->entries()) {
532 if (entry
->vendor_id() == device_entry
->vendor_id() &&
533 entry
->product_id() == device_entry
->product_id() &&
534 entry
->serial_number() == device_entry
->serial_number()) {
539 device_permissions
->entries_
.insert(device_entry
);
540 SaveDevicePermissionEntry(context_
, extension_id
, device_entry
);
541 } else if (!ContainsKey(device_permissions
->ephemeral_usb_devices_
,
543 // Non-persistent devices cannot be reliably identified when they are
544 // reconnected so such devices are only remembered until disconnect.
545 // Register an observer here so that this set doesn't grow undefinitely.
546 device_permissions
->entries_
.insert(device_entry
);
547 device_permissions
->ephemeral_usb_devices_
[device
.get()] = device_entry
;
549 // Only start observing when an ephemeral device has been added so that
550 // UsbService is not automatically initialized on profile creation (which it
551 // would be if this call were in the constructor).
552 UsbService
* usb_service
= device::DeviceClient::Get()->GetUsbService();
553 if (!usb_service_observer_
.IsObserving(usb_service
)) {
554 usb_service_observer_
.Add(usb_service
);
559 void DevicePermissionsManager::AllowHidDevice(
560 const std::string
& extension_id
,
561 scoped_refptr
<HidDeviceInfo
> device
) {
562 DCHECK(thread_checker_
.CalledOnValidThread());
563 DevicePermissions
* device_permissions
= GetForExtension(extension_id
);
565 scoped_refptr
<DevicePermissionEntry
> device_entry(
566 new DevicePermissionEntry(device
));
568 if (device_entry
->IsPersistent()) {
569 for (const auto& entry
: device_permissions
->entries()) {
570 if (entry
->vendor_id() == device_entry
->vendor_id() &&
571 entry
->product_id() == device_entry
->product_id() &&
572 entry
->serial_number() == device_entry
->serial_number()) {
577 device_permissions
->entries_
.insert(device_entry
);
578 SaveDevicePermissionEntry(context_
, extension_id
, device_entry
);
579 } else if (!ContainsKey(device_permissions
->ephemeral_hid_devices_
,
581 // Non-persistent devices cannot be reliably identified when they are
582 // reconnected so such devices are only remembered until disconnect.
583 // Register an observer here so that this set doesn't grow undefinitely.
584 device_permissions
->entries_
.insert(device_entry
);
585 device_permissions
->ephemeral_hid_devices_
[device
.get()] = device_entry
;
587 // Only start observing when an ephemeral device has been added so that
588 // HidService is not automatically initialized on profile creation (which it
589 // would be if this call were in the constructor).
590 HidService
* hid_service
= device::DeviceClient::Get()->GetHidService();
591 if (!hid_service_observer_
.IsObserving(hid_service
)) {
592 hid_service_observer_
.Add(hid_service
);
597 void DevicePermissionsManager::UpdateLastUsed(
598 const std::string
& extension_id
,
599 scoped_refptr
<DevicePermissionEntry
> entry
) {
600 DCHECK(thread_checker_
.CalledOnValidThread());
601 entry
->set_last_used(base::Time::Now());
602 if (entry
->IsPersistent()) {
603 UpdateDevicePermissionEntry(context_
, extension_id
, entry
);
607 void DevicePermissionsManager::RemoveEntry(
608 const std::string
& extension_id
,
609 scoped_refptr
<DevicePermissionEntry
> entry
) {
610 DCHECK(thread_checker_
.CalledOnValidThread());
611 DevicePermissions
* device_permissions
= GetInternal(extension_id
);
612 DCHECK(device_permissions
);
613 DCHECK(ContainsKey(device_permissions
->entries_
, entry
));
614 device_permissions
->entries_
.erase(entry
);
615 if (entry
->IsPersistent()) {
616 RemoveDevicePermissionEntry(context_
, extension_id
, entry
);
617 } else if (entry
->type_
== DevicePermissionEntry::Type::USB
) {
618 device_permissions
->ephemeral_usb_devices_
.erase(entry
->usb_device_
.get());
619 } else if (entry
->type_
== DevicePermissionEntry::Type::HID
) {
620 device_permissions
->ephemeral_hid_devices_
.erase(entry
->hid_device_
.get());
626 void DevicePermissionsManager::Clear(const std::string
& extension_id
) {
627 DCHECK(thread_checker_
.CalledOnValidThread());
629 ClearDevicePermissionEntries(ExtensionPrefs::Get(context_
), extension_id
);
630 DevicePermissions
* device_permissions
= GetInternal(extension_id
);
631 if (device_permissions
) {
632 extension_id_to_device_permissions_
.erase(extension_id
);
633 delete device_permissions
;
637 DevicePermissionsManager::DevicePermissionsManager(
638 content::BrowserContext
* context
)
640 usb_service_observer_(this),
641 hid_service_observer_(this) {
644 DevicePermissionsManager::~DevicePermissionsManager() {
645 for (const auto& map_entry
: extension_id_to_device_permissions_
) {
646 DevicePermissions
* device_permissions
= map_entry
.second
;
647 delete device_permissions
;
651 DevicePermissions
* DevicePermissionsManager::GetInternal(
652 const std::string
& extension_id
) const {
653 std::map
<std::string
, DevicePermissions
*>::const_iterator it
=
654 extension_id_to_device_permissions_
.find(extension_id
);
655 if (it
!= extension_id_to_device_permissions_
.end()) {
662 void DevicePermissionsManager::OnDeviceRemovedCleanup(
663 scoped_refptr
<UsbDevice
> device
) {
664 DCHECK(thread_checker_
.CalledOnValidThread());
665 for (const auto& map_entry
: extension_id_to_device_permissions_
) {
666 // An ephemeral device cannot be identified if it is reconnected and so
667 // permission to access it is cleared on disconnect.
668 DevicePermissions
* device_permissions
= map_entry
.second
;
669 const auto& device_entry
=
670 device_permissions
->ephemeral_usb_devices_
.find(device
.get());
671 if (device_entry
!= device_permissions
->ephemeral_usb_devices_
.end()) {
672 device_permissions
->entries_
.erase(device_entry
->second
);
673 device_permissions
->ephemeral_usb_devices_
.erase(device_entry
);
678 void DevicePermissionsManager::OnDeviceRemovedCleanup(
679 scoped_refptr
<device::HidDeviceInfo
> device
) {
680 DCHECK(thread_checker_
.CalledOnValidThread());
681 for (const auto& map_entry
: extension_id_to_device_permissions_
) {
682 // An ephemeral device cannot be identified if it is reconnected and so
683 // permission to access it is cleared on disconnect.
684 DevicePermissions
* device_permissions
= map_entry
.second
;
685 const auto& device_entry
=
686 device_permissions
->ephemeral_hid_devices_
.find(device
.get());
687 if (device_entry
!= device_permissions
->ephemeral_hid_devices_
.end()) {
688 device_permissions
->entries_
.erase(device_entry
->second
);
689 device_permissions
->ephemeral_hid_devices_
.erase(device_entry
);
695 DevicePermissionsManager
* DevicePermissionsManagerFactory::GetForBrowserContext(
696 content::BrowserContext
* context
) {
697 return static_cast<DevicePermissionsManager
*>(
698 GetInstance()->GetServiceForBrowserContext(context
, true));
702 DevicePermissionsManagerFactory
*
703 DevicePermissionsManagerFactory::GetInstance() {
704 return base::Singleton
<DevicePermissionsManagerFactory
>::get();
707 DevicePermissionsManagerFactory::DevicePermissionsManagerFactory()
708 : BrowserContextKeyedServiceFactory(
709 "DevicePermissionsManager",
710 BrowserContextDependencyManager::GetInstance()) {
713 DevicePermissionsManagerFactory::~DevicePermissionsManagerFactory() {
716 KeyedService
* DevicePermissionsManagerFactory::BuildServiceInstanceFor(
717 content::BrowserContext
* context
) const {
718 return new DevicePermissionsManager(context
);
721 BrowserContext
* DevicePermissionsManagerFactory::GetBrowserContextToUse(
722 BrowserContext
* context
) const {
723 // Return the original (possibly off-the-record) browser context so that a
724 // separate instance of the DevicePermissionsManager is used in incognito
725 // mode. The parent class's implemenation returns NULL.
729 } // namespace extensions