| OLD | NEW |
| (Empty) |
| 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 "components/storage_monitor/media_transfer_protocol_device_observer_lin
ux.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/files/file_path.h" | |
| 10 #include "base/stl_util.h" | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "base/strings/string_split.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 #include "components/storage_monitor/media_storage_util.h" | |
| 15 #include "components/storage_monitor/removable_device_constants.h" | |
| 16 #include "device/media_transfer_protocol/mtp_storage_info.pb.h" | |
| 17 | |
| 18 namespace storage_monitor { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Device root path constant. | |
| 23 const char kRootPath[] = "/"; | |
| 24 | |
| 25 // Constructs and returns the location of the device using the |storage_name|. | |
| 26 std::string GetDeviceLocationFromStorageName(const std::string& storage_name) { | |
| 27 // Construct a dummy device path using the storage name. This is only used | |
| 28 // for registering device media file system. | |
| 29 // E.g.: If the |storage_name| is "usb:2,2:12345" then "/usb:2,2:12345" is the | |
| 30 // device location. | |
| 31 DCHECK(!storage_name.empty()); | |
| 32 return kRootPath + storage_name; | |
| 33 } | |
| 34 | |
| 35 // Returns the storage identifier of the device from the given |storage_name|. | |
| 36 // E.g. If the |storage_name| is "usb:2,2:65537", the storage identifier is | |
| 37 // "65537". | |
| 38 std::string GetStorageIdFromStorageName(const std::string& storage_name) { | |
| 39 std::vector<base::StringPiece> name_parts = base::SplitStringPiece( | |
| 40 storage_name, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
| 41 return name_parts.size() == 3 ? name_parts[2].as_string() : std::string(); | |
| 42 } | |
| 43 | |
| 44 // Returns a unique device id from the given |storage_info|. | |
| 45 std::string GetDeviceIdFromStorageInfo(const MtpStorageInfo& storage_info) { | |
| 46 const std::string storage_id = | |
| 47 GetStorageIdFromStorageName(storage_info.storage_name()); | |
| 48 if (storage_id.empty()) | |
| 49 return std::string(); | |
| 50 | |
| 51 // Some devices have multiple data stores. Therefore, include storage id as | |
| 52 // part of unique id along with vendor, model and volume information. | |
| 53 const std::string vendor_id = base::UintToString(storage_info.vendor_id()); | |
| 54 const std::string model_id = base::UintToString(storage_info.product_id()); | |
| 55 return StorageInfo::MakeDeviceId( | |
| 56 StorageInfo::MTP_OR_PTP, | |
| 57 kVendorModelVolumeStoragePrefix + vendor_id + ":" + model_id + ":" + | |
| 58 storage_info.volume_identifier() + ":" + storage_id); | |
| 59 } | |
| 60 | |
| 61 // Returns the |data_store_id| string in the required format. | |
| 62 // If the |data_store_id| is 65537, this function returns " (65537)". | |
| 63 std::string GetFormattedIdString(const std::string& data_store_id) { | |
| 64 return ("(" + data_store_id + ")"); | |
| 65 } | |
| 66 | |
| 67 // Helper function to get device label from storage information. | |
| 68 base::string16 GetDeviceLabelFromStorageInfo( | |
| 69 const MtpStorageInfo& storage_info) { | |
| 70 std::string device_label; | |
| 71 const std::string& vendor_name = storage_info.vendor(); | |
| 72 device_label = vendor_name; | |
| 73 | |
| 74 const std::string& product_name = storage_info.product(); | |
| 75 if (!product_name.empty()) { | |
| 76 if (!device_label.empty()) | |
| 77 device_label += " "; | |
| 78 device_label += product_name; | |
| 79 } | |
| 80 | |
| 81 // Add the data store id to the device label. | |
| 82 if (!device_label.empty()) { | |
| 83 const std::string& volume_id = storage_info.volume_identifier(); | |
| 84 if (!volume_id.empty()) { | |
| 85 device_label += GetFormattedIdString(volume_id); | |
| 86 } else { | |
| 87 const std::string data_store_id = | |
| 88 GetStorageIdFromStorageName(storage_info.storage_name()); | |
| 89 if (!data_store_id.empty()) | |
| 90 device_label += GetFormattedIdString(data_store_id); | |
| 91 } | |
| 92 } | |
| 93 return base::UTF8ToUTF16(device_label); | |
| 94 } | |
| 95 | |
| 96 // Helper function to get the device storage details such as device id, label | |
| 97 // and location. On success and fills in |id|, |label|, |location|, | |
| 98 // |vendor_name|, and |product_name|. | |
| 99 void GetStorageInfo(const std::string& storage_name, | |
| 100 device::MediaTransferProtocolManager* mtp_manager, | |
| 101 std::string* id, | |
| 102 base::string16* label, | |
| 103 std::string* location, | |
| 104 base::string16* vendor_name, | |
| 105 base::string16* product_name) { | |
| 106 DCHECK(!storage_name.empty()); | |
| 107 const MtpStorageInfo* storage_info = | |
| 108 mtp_manager->GetStorageInfo(storage_name); | |
| 109 | |
| 110 if (!storage_info) | |
| 111 return; | |
| 112 | |
| 113 *id = GetDeviceIdFromStorageInfo(*storage_info); | |
| 114 *label = GetDeviceLabelFromStorageInfo(*storage_info); | |
| 115 *location = GetDeviceLocationFromStorageName(storage_name); | |
| 116 *vendor_name = base::UTF8ToUTF16(storage_info->vendor()); | |
| 117 *product_name = base::UTF8ToUTF16(storage_info->product()); | |
| 118 } | |
| 119 | |
| 120 } // namespace | |
| 121 | |
| 122 MediaTransferProtocolDeviceObserverLinux:: | |
| 123 MediaTransferProtocolDeviceObserverLinux( | |
| 124 StorageMonitor::Receiver* receiver, | |
| 125 device::MediaTransferProtocolManager* mtp_manager) | |
| 126 : mtp_manager_(mtp_manager), | |
| 127 get_storage_info_func_(&GetStorageInfo), | |
| 128 notifications_(receiver) { | |
| 129 mtp_manager_->AddObserver(this); | |
| 130 EnumerateStorages(); | |
| 131 } | |
| 132 | |
| 133 // This constructor is only used by unit tests. | |
| 134 MediaTransferProtocolDeviceObserverLinux:: | |
| 135 MediaTransferProtocolDeviceObserverLinux( | |
| 136 StorageMonitor::Receiver* receiver, | |
| 137 device::MediaTransferProtocolManager* mtp_manager, | |
| 138 GetStorageInfoFunc get_storage_info_func) | |
| 139 : mtp_manager_(mtp_manager), | |
| 140 get_storage_info_func_(get_storage_info_func), | |
| 141 notifications_(receiver) { | |
| 142 } | |
| 143 | |
| 144 MediaTransferProtocolDeviceObserverLinux:: | |
| 145 ~MediaTransferProtocolDeviceObserverLinux() { | |
| 146 mtp_manager_->RemoveObserver(this); | |
| 147 } | |
| 148 | |
| 149 bool MediaTransferProtocolDeviceObserverLinux::GetStorageInfoForPath( | |
| 150 const base::FilePath& path, | |
| 151 StorageInfo* storage_info) const { | |
| 152 DCHECK(storage_info); | |
| 153 | |
| 154 if (!path.IsAbsolute()) | |
| 155 return false; | |
| 156 | |
| 157 std::vector<base::FilePath::StringType> path_components; | |
| 158 path.GetComponents(&path_components); | |
| 159 if (path_components.size() < 2) | |
| 160 return false; | |
| 161 | |
| 162 // First and second component of the path specifies the device location. | |
| 163 // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the | |
| 164 // device location. | |
| 165 StorageLocationToInfoMap::const_iterator info_it = | |
| 166 storage_map_.find(GetDeviceLocationFromStorageName(path_components[1])); | |
| 167 if (info_it == storage_map_.end()) | |
| 168 return false; | |
| 169 | |
| 170 *storage_info = info_it->second; | |
| 171 return true; | |
| 172 } | |
| 173 | |
| 174 void MediaTransferProtocolDeviceObserverLinux::EjectDevice( | |
| 175 const std::string& device_id, | |
| 176 base::Callback<void(StorageMonitor::EjectStatus)> callback) { | |
| 177 std::string location; | |
| 178 if (!GetLocationForDeviceId(device_id, &location)) { | |
| 179 callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE); | |
| 180 return; | |
| 181 } | |
| 182 | |
| 183 // TODO(thestig): Change this to tell the mtp manager to eject the device. | |
| 184 | |
| 185 StorageChanged(false, location); | |
| 186 callback.Run(StorageMonitor::EJECT_OK); | |
| 187 } | |
| 188 | |
| 189 // device::MediaTransferProtocolManager::Observer override. | |
| 190 void MediaTransferProtocolDeviceObserverLinux::StorageChanged( | |
| 191 bool is_attached, | |
| 192 const std::string& storage_name) { | |
| 193 DCHECK(!storage_name.empty()); | |
| 194 | |
| 195 // New storage is attached. | |
| 196 if (is_attached) { | |
| 197 std::string device_id; | |
| 198 base::string16 storage_label; | |
| 199 std::string location; | |
| 200 base::string16 vendor_name; | |
| 201 base::string16 product_name; | |
| 202 get_storage_info_func_(storage_name, mtp_manager_, | |
| 203 &device_id, &storage_label, &location, | |
| 204 &vendor_name, &product_name); | |
| 205 | |
| 206 // Keep track of device id and device name to see how often we receive | |
| 207 // empty values. | |
| 208 MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id, | |
| 209 storage_label); | |
| 210 if (device_id.empty() || storage_label.empty()) | |
| 211 return; | |
| 212 | |
| 213 DCHECK(!base::ContainsKey(storage_map_, location)); | |
| 214 | |
| 215 StorageInfo storage_info(device_id, location, storage_label, | |
| 216 vendor_name, product_name, 0); | |
| 217 storage_map_[location] = storage_info; | |
| 218 notifications_->ProcessAttach(storage_info); | |
| 219 } else { | |
| 220 // Existing storage is detached. | |
| 221 StorageLocationToInfoMap::iterator it = | |
| 222 storage_map_.find(GetDeviceLocationFromStorageName(storage_name)); | |
| 223 if (it == storage_map_.end()) | |
| 224 return; | |
| 225 notifications_->ProcessDetach(it->second.device_id()); | |
| 226 storage_map_.erase(it); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 void MediaTransferProtocolDeviceObserverLinux::EnumerateStorages() { | |
| 231 typedef std::vector<std::string> StorageList; | |
| 232 StorageList storages = mtp_manager_->GetStorages(); | |
| 233 for (StorageList::const_iterator storage_iter = storages.begin(); | |
| 234 storage_iter != storages.end(); ++storage_iter) { | |
| 235 StorageChanged(true, *storage_iter); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 bool MediaTransferProtocolDeviceObserverLinux::GetLocationForDeviceId( | |
| 240 const std::string& device_id, std::string* location) const { | |
| 241 for (StorageLocationToInfoMap::const_iterator it = storage_map_.begin(); | |
| 242 it != storage_map_.end(); ++it) { | |
| 243 if (it->second.device_id() == device_id) { | |
| 244 *location = it->first; | |
| 245 return true; | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 return false; | |
| 250 } | |
| 251 | |
| 252 } // namespace storage_monitor | |
| OLD | NEW |