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 "apps/saved_devices_service.h"
10 #include "apps/saved_devices_service_factory.h"
11 #include "base/basictypes.h"
12 #include "base/values.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/notification_service.h"
17 #include "device/usb/usb_device.h"
18 #include "device/usb/usb_device_handle.h"
19 #include "extensions/browser/extension_host.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/extension_util.h"
23 #include "extensions/browser/notification_types.h"
24 #include "extensions/common/permissions/api_permission.h"
25 #include "extensions/common/permissions/permission_set.h"
26 #include "extensions/common/permissions/permissions_data.h"
30 using device::UsbDevice
;
31 using device::UsbDeviceHandle
;
32 using extensions::APIPermission
;
33 using extensions::Extension
;
34 using extensions::ExtensionHost
;
35 using extensions::ExtensionPrefs
;
41 // The device that the app has permission to access.
42 const char kDevices
[] = "devices";
44 // The type of device saved.
45 const char kDeviceType
[] = "type";
47 // Type identifier for USB devices.
48 const char kDeviceTypeUsb
[] = "usb";
50 // The vendor ID of the device that the app had permission to access.
51 const char kDeviceVendorId
[] = "vendor_id";
53 // The product ID of the device that the app had permission to access.
54 const char kDeviceProductId
[] = "product_id";
56 // The serial number of the device that the app has permission to access.
57 const char kDeviceSerialNumber
[] = "serial_number";
59 // Persists a SavedDeviceEntry in ExtensionPrefs.
60 void AddSavedDeviceEntry(Profile
* profile
,
61 const std::string
& extension_id
,
62 const SavedDeviceEntry
& device
) {
63 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(profile
);
64 ExtensionPrefs::ScopedListUpdate
update(prefs
, extension_id
, kDevices
);
65 base::ListValue
* devices
= update
.Get();
67 devices
= update
.Create();
70 base::Value
* device_entry
= device
.ToValue();
71 DCHECK(devices
->Find(*device_entry
) == devices
->end());
72 devices
->Append(device_entry
);
75 // Clears all SavedDeviceEntry for the app from ExtensionPrefs.
76 void ClearSavedDeviceEntries(ExtensionPrefs
* prefs
,
77 const std::string
& extension_id
) {
78 prefs
->UpdateExtensionPref(extension_id
, kDevices
, NULL
);
81 // Returns all SavedDeviceEntries for the app.
82 std::vector
<SavedDeviceEntry
> GetSavedDeviceEntries(
83 ExtensionPrefs
* prefs
,
84 const std::string
& extension_id
) {
85 std::vector
<SavedDeviceEntry
> result
;
86 const base::ListValue
* devices
= NULL
;
87 if (!prefs
->ReadPrefAsList(extension_id
, kDevices
, &devices
)) {
91 for (base::ListValue::const_iterator it
= devices
->begin();
94 const base::DictionaryValue
* device_entry
= NULL
;
95 if (!(*it
)->GetAsDictionary(&device_entry
)) {
99 if (!device_entry
->GetIntegerWithoutPathExpansion(kDeviceVendorId
,
101 vendor_id
< 0 || vendor_id
> UINT16_MAX
) {
105 if (!device_entry
->GetIntegerWithoutPathExpansion(kDeviceProductId
,
107 product_id
< 0 || product_id
> UINT16_MAX
) {
110 base::string16 serial_number
;
111 if (!device_entry
->GetStringWithoutPathExpansion(kDeviceSerialNumber
,
116 result
.push_back(SavedDeviceEntry(vendor_id
, product_id
, serial_number
));
123 SavedDeviceEntry::SavedDeviceEntry(uint16_t vendor_id
,
125 const base::string16
& serial_number
)
126 : vendor_id(vendor_id
),
127 product_id(product_id
),
128 serial_number(serial_number
) {
131 base::Value
* SavedDeviceEntry::ToValue() const {
132 base::DictionaryValue
* device_entry_dict
= new base::DictionaryValue();
133 device_entry_dict
->SetStringWithoutPathExpansion(kDeviceType
, kDeviceTypeUsb
);
134 device_entry_dict
->SetIntegerWithoutPathExpansion(kDeviceVendorId
, vendor_id
);
135 device_entry_dict
->SetIntegerWithoutPathExpansion(kDeviceProductId
,
137 device_entry_dict
->SetStringWithoutPathExpansion(kDeviceSerialNumber
,
139 return device_entry_dict
;
142 bool SavedDevicesService::SavedDevices::IsRegistered(
143 scoped_refptr
<UsbDevice
> device
) const {
144 if (ephemeral_devices_
.find(device
) != ephemeral_devices_
.end()) {
148 bool have_serial_number
= false;
149 base::string16 serial_number
;
150 for (std::vector
<SavedDeviceEntry
>::const_iterator it
=
151 persistent_devices_
.begin();
152 it
!= persistent_devices_
.end();
154 if (it
->vendor_id
!= device
->vendor_id()) {
157 if (it
->product_id
!= device
->product_id()) {
160 if (!have_serial_number
) {
161 scoped_refptr
<UsbDeviceHandle
> device_handle
= device
->Open();
162 if (!device_handle
.get()) {
165 if (!device_handle
->GetSerial(&serial_number
)) {
168 have_serial_number
= true;
170 if (it
->serial_number
!= serial_number
) {
178 void SavedDevicesService::SavedDevices::RegisterDevice(
179 scoped_refptr
<device::UsbDevice
> device
,
180 base::string16
* serial_number
) {
182 for (std::vector
<SavedDeviceEntry
>::const_iterator it
=
183 persistent_devices_
.begin();
184 it
!= persistent_devices_
.end();
186 if (it
->vendor_id
!= device
->vendor_id()) {
189 if (it
->product_id
!= device
->product_id()) {
192 if (it
->serial_number
== *serial_number
) {
196 SavedDeviceEntry device_entry
= SavedDeviceEntry(
197 device
->vendor_id(), device
->product_id(), *serial_number
);
198 persistent_devices_
.push_back(device_entry
);
200 content::BrowserThread::PostTask(
201 content::BrowserThread::UI
,
203 base::Bind(AddSavedDeviceEntry
, profile_
, extension_id_
, device_entry
));
205 // Without a serial number a device cannot be reliably identified when it
206 // is reconnected so such devices are only remembered until disconnect.
207 // Register an observer here so that this set doesn't grow undefinitely.
208 ephemeral_devices_
.insert(device
);
209 device
->AddObserver(this);
213 SavedDevicesService::SavedDevices::SavedDevices(Profile
* profile
,
214 const std::string
& extension_id
)
215 : profile_(profile
), extension_id_(extension_id
) {
216 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(profile_
);
217 persistent_devices_
= GetSavedDeviceEntries(prefs
, extension_id_
);
220 SavedDevicesService::SavedDevices::~SavedDevices() {
221 // Only ephemeral devices have an observer registered.
222 for (std::set
<scoped_refptr
<UsbDevice
> >::iterator it
=
223 ephemeral_devices_
.begin();
224 it
!= ephemeral_devices_
.end();
226 (*it
)->RemoveObserver(this);
230 void SavedDevicesService::SavedDevices::OnDisconnect(
231 scoped_refptr
<UsbDevice
> device
) {
232 // Permission for an ephemeral device lasts only as long as the device is
234 ephemeral_devices_
.erase(device
);
235 device
->RemoveObserver(this);
238 SavedDevicesService::SavedDevicesService(Profile
* profile
) : profile_(profile
) {
240 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
,
241 content::NotificationService::AllSources());
243 chrome::NOTIFICATION_APP_TERMINATING
,
244 content::NotificationService::AllSources());
247 SavedDevicesService::~SavedDevicesService() {
248 for (std::map
<std::string
, SavedDevices
*>::iterator it
=
249 extension_id_to_saved_devices_
.begin();
250 it
!= extension_id_to_saved_devices_
.end();
257 SavedDevicesService
* SavedDevicesService::Get(Profile
* profile
) {
258 return SavedDevicesServiceFactory::GetForProfile(profile
);
261 SavedDevicesService::SavedDevices
* SavedDevicesService::GetOrInsert(
262 const std::string
& extension_id
) {
263 SavedDevices
* saved_devices
= Get(extension_id
);
265 return saved_devices
;
268 saved_devices
= new SavedDevices(profile_
, extension_id
);
269 extension_id_to_saved_devices_
[extension_id
] = saved_devices
;
270 return saved_devices
;
273 std::vector
<SavedDeviceEntry
> SavedDevicesService::GetAllDevices(
274 const std::string
& extension_id
) const {
275 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(profile_
);
276 return GetSavedDeviceEntries(prefs
, extension_id
);
279 void SavedDevicesService::Clear(const std::string
& extension_id
) {
280 DCHECK(thread_checker_
.CalledOnValidThread());
281 ClearSavedDeviceEntries(ExtensionPrefs::Get(profile_
), extension_id
);
282 std::map
<std::string
, SavedDevices
*>::iterator it
=
283 extension_id_to_saved_devices_
.find(extension_id
);
284 if (it
!= extension_id_to_saved_devices_
.end()) {
286 extension_id_to_saved_devices_
.erase(it
);
290 void SavedDevicesService::Observe(int type
,
291 const content::NotificationSource
& source
,
292 const content::NotificationDetails
& details
) {
294 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
: {
295 Clear(content::Details
<ExtensionHost
>(details
)->extension_id());
299 case chrome::NOTIFICATION_APP_TERMINATING
: {
300 // Stop listening to NOTIFICATION_EXTENSION_HOST_DESTROYED in particular
301 // as all extension hosts will be destroyed as a result of shutdown.
302 registrar_
.RemoveAll();
308 SavedDevicesService::SavedDevices
* SavedDevicesService::Get(
309 const std::string
& extension_id
) const {
310 DCHECK(thread_checker_
.CalledOnValidThread());
311 std::map
<std::string
, SavedDevices
*>::const_iterator it
=
312 extension_id_to_saved_devices_
.find(extension_id
);
313 if (it
!= extension_id_to_saved_devices_
.end()) {