Home | History | Annotate | Download | only in apps
      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.
      4 
      5 #include "apps/saved_devices_service.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     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"
     27 
     28 namespace apps {
     29 
     30 using device::UsbDevice;
     31 using device::UsbDeviceHandle;
     32 using extensions::APIPermission;
     33 using extensions::Extension;
     34 using extensions::ExtensionHost;
     35 using extensions::ExtensionPrefs;
     36 
     37 namespace {
     38 
     39 // Preference keys
     40 
     41 // The device that the app has permission to access.
     42 const char kDevices[] = "devices";
     43 
     44 // The type of device saved.
     45 const char kDeviceType[] = "type";
     46 
     47 // Type identifier for USB devices.
     48 const char kDeviceTypeUsb[] = "usb";
     49 
     50 // The vendor ID of the device that the app had permission to access.
     51 const char kDeviceVendorId[] = "vendor_id";
     52 
     53 // The product ID of the device that the app had permission to access.
     54 const char kDeviceProductId[] = "product_id";
     55 
     56 // The serial number of the device that the app has permission to access.
     57 const char kDeviceSerialNumber[] = "serial_number";
     58 
     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();
     66   if (!devices) {
     67     devices = update.Create();
     68   }
     69 
     70   base::Value* device_entry = device.ToValue();
     71   DCHECK(devices->Find(*device_entry) == devices->end());
     72   devices->Append(device_entry);
     73 }
     74 
     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);
     79 }
     80 
     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)) {
     88     return result;
     89   }
     90 
     91   for (base::ListValue::const_iterator it = devices->begin();
     92        it != devices->end();
     93        ++it) {
     94     const base::DictionaryValue* device_entry = NULL;
     95     if (!(*it)->GetAsDictionary(&device_entry)) {
     96       continue;
     97     }
     98     int vendor_id;
     99     if (!device_entry->GetIntegerWithoutPathExpansion(kDeviceVendorId,
    100                                                       &vendor_id) ||
    101         vendor_id < 0 || vendor_id > UINT16_MAX) {
    102       continue;
    103     }
    104     int product_id;
    105     if (!device_entry->GetIntegerWithoutPathExpansion(kDeviceProductId,
    106                                                       &product_id) ||
    107         product_id < 0 || product_id > UINT16_MAX) {
    108       continue;
    109     }
    110     base::string16 serial_number;
    111     if (!device_entry->GetStringWithoutPathExpansion(kDeviceSerialNumber,
    112                                                      &serial_number)) {
    113       continue;
    114     }
    115 
    116     result.push_back(SavedDeviceEntry(vendor_id, product_id, serial_number));
    117   }
    118   return result;
    119 }
    120 
    121 }  // namespace
    122 
    123 SavedDeviceEntry::SavedDeviceEntry(uint16_t vendor_id,
    124                                    uint16_t product_id,
    125                                    const base::string16& serial_number)
    126     : vendor_id(vendor_id),
    127       product_id(product_id),
    128       serial_number(serial_number) {
    129 }
    130 
    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,
    136                                                     product_id);
    137   device_entry_dict->SetStringWithoutPathExpansion(kDeviceSerialNumber,
    138                                                    serial_number);
    139   return device_entry_dict;
    140 }
    141 
    142 bool SavedDevicesService::SavedDevices::IsRegistered(
    143     scoped_refptr<UsbDevice> device) const {
    144   if (ephemeral_devices_.find(device) != ephemeral_devices_.end()) {
    145     return true;
    146   }
    147 
    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();
    153        ++it) {
    154     if (it->vendor_id != device->vendor_id()) {
    155       continue;
    156     }
    157     if (it->product_id != device->product_id()) {
    158       continue;
    159     }
    160     if (!have_serial_number) {
    161       if (!device->GetSerialNumber(&serial_number)) {
    162         break;
    163       }
    164       have_serial_number = true;
    165     }
    166     if (it->serial_number != serial_number) {
    167       continue;
    168     }
    169     return true;
    170   }
    171   return false;
    172 }
    173 
    174 void SavedDevicesService::SavedDevices::RegisterDevice(
    175     scoped_refptr<device::UsbDevice> device,
    176     base::string16* serial_number) {
    177   if (serial_number) {
    178     for (std::vector<SavedDeviceEntry>::const_iterator it =
    179              persistent_devices_.begin();
    180          it != persistent_devices_.end();
    181          ++it) {
    182       if (it->vendor_id != device->vendor_id()) {
    183         continue;
    184       }
    185       if (it->product_id != device->product_id()) {
    186         continue;
    187       }
    188       if (it->serial_number == *serial_number) {
    189         return;
    190       }
    191     }
    192     SavedDeviceEntry device_entry = SavedDeviceEntry(
    193         device->vendor_id(), device->product_id(), *serial_number);
    194     persistent_devices_.push_back(device_entry);
    195 
    196     content::BrowserThread::PostTask(
    197         content::BrowserThread::UI,
    198         FROM_HERE,
    199         base::Bind(AddSavedDeviceEntry, profile_, extension_id_, device_entry));
    200   } else {
    201     // Without a serial number a device cannot be reliably identified when it
    202     // is reconnected so such devices are only remembered until disconnect.
    203     // Register an observer here so that this set doesn't grow undefinitely.
    204     ephemeral_devices_.insert(device);
    205     device->AddObserver(this);
    206   }
    207 }
    208 
    209 SavedDevicesService::SavedDevices::SavedDevices(Profile* profile,
    210                                                 const std::string& extension_id)
    211     : profile_(profile), extension_id_(extension_id) {
    212   ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
    213   persistent_devices_ = GetSavedDeviceEntries(prefs, extension_id_);
    214 }
    215 
    216 SavedDevicesService::SavedDevices::~SavedDevices() {
    217   // Only ephemeral devices have an observer registered.
    218   for (std::set<scoped_refptr<UsbDevice> >::iterator it =
    219            ephemeral_devices_.begin();
    220        it != ephemeral_devices_.end();
    221        ++it) {
    222     (*it)->RemoveObserver(this);
    223   }
    224 }
    225 
    226 void SavedDevicesService::SavedDevices::OnDisconnect(
    227     scoped_refptr<UsbDevice> device) {
    228   // Permission for an ephemeral device lasts only as long as the device is
    229   // plugged in.
    230   ephemeral_devices_.erase(device);
    231   device->RemoveObserver(this);
    232 }
    233 
    234 SavedDevicesService::SavedDevicesService(Profile* profile) : profile_(profile) {
    235   registrar_.Add(this,
    236                  extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    237                  content::NotificationService::AllSources());
    238   registrar_.Add(this,
    239                  chrome::NOTIFICATION_APP_TERMINATING,
    240                  content::NotificationService::AllSources());
    241 }
    242 
    243 SavedDevicesService::~SavedDevicesService() {
    244   for (std::map<std::string, SavedDevices*>::iterator it =
    245            extension_id_to_saved_devices_.begin();
    246        it != extension_id_to_saved_devices_.end();
    247        ++it) {
    248     delete it->second;
    249   }
    250 }
    251 
    252 // static
    253 SavedDevicesService* SavedDevicesService::Get(Profile* profile) {
    254   return SavedDevicesServiceFactory::GetForProfile(profile);
    255 }
    256 
    257 SavedDevicesService::SavedDevices* SavedDevicesService::GetOrInsert(
    258     const std::string& extension_id) {
    259   SavedDevices* saved_devices = Get(extension_id);
    260   if (saved_devices) {
    261     return saved_devices;
    262   }
    263 
    264   saved_devices = new SavedDevices(profile_, extension_id);
    265   extension_id_to_saved_devices_[extension_id] = saved_devices;
    266   return saved_devices;
    267 }
    268 
    269 std::vector<SavedDeviceEntry> SavedDevicesService::GetAllDevices(
    270     const std::string& extension_id) const {
    271   ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
    272   return GetSavedDeviceEntries(prefs, extension_id);
    273 }
    274 
    275 void SavedDevicesService::Clear(const std::string& extension_id) {
    276   DCHECK(thread_checker_.CalledOnValidThread());
    277   ClearSavedDeviceEntries(ExtensionPrefs::Get(profile_), extension_id);
    278   std::map<std::string, SavedDevices*>::iterator it =
    279       extension_id_to_saved_devices_.find(extension_id);
    280   if (it != extension_id_to_saved_devices_.end()) {
    281     delete it->second;
    282     extension_id_to_saved_devices_.erase(it);
    283   }
    284 }
    285 
    286 void SavedDevicesService::Observe(int type,
    287                                   const content::NotificationSource& source,
    288                                   const content::NotificationDetails& details) {
    289   switch (type) {
    290     case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
    291       Clear(content::Details<ExtensionHost>(details)->extension_id());
    292       break;
    293     }
    294 
    295     case chrome::NOTIFICATION_APP_TERMINATING: {
    296       // Stop listening to NOTIFICATION_EXTENSION_HOST_DESTROYED in particular
    297       // as all extension hosts will be destroyed as a result of shutdown.
    298       registrar_.RemoveAll();
    299       break;
    300     }
    301   }
    302 }
    303 
    304 SavedDevicesService::SavedDevices* SavedDevicesService::Get(
    305     const std::string& extension_id) const {
    306   DCHECK(thread_checker_.CalledOnValidThread());
    307   std::map<std::string, SavedDevices*>::const_iterator it =
    308       extension_id_to_saved_devices_.find(extension_id);
    309   if (it != extension_id_to_saved_devices_.end()) {
    310     return it->second;
    311   }
    312 
    313   return NULL;
    314 }
    315 
    316 }  // namespace apps
    317