Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / components / storage_monitor / media_transfer_protocol_device_observer_linux.cc
blob6c3e4b00696dcd8b89adf66940abd078979e0c8d
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 "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
7 #include <vector>
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"
18 namespace storage_monitor {
20 namespace {
22 // Device root path constant.
23 const char kRootPath[] = "/";
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;
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<std::string> name_parts;
40 base::SplitString(storage_name, ':', &name_parts);
41 return name_parts.size() == 3 ? name_parts[2] : std::string();
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();
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);
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 + ")");
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;
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;
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);
93 return base::UTF8ToUTF16(device_label);
96 // Helper function to get the device storage details such as device id, label
97 // and location. On success and fills in |id|, |label| and |location|.
98 void GetStorageInfo(const std::string& storage_name,
99 device::MediaTransferProtocolManager* mtp_manager,
100 std::string* id,
101 base::string16* label,
102 std::string* location) {
103 DCHECK(!storage_name.empty());
104 const MtpStorageInfo* storage_info =
105 mtp_manager->GetStorageInfo(storage_name);
107 if (!storage_info)
108 return;
110 *id = GetDeviceIdFromStorageInfo(*storage_info);
111 *label = GetDeviceLabelFromStorageInfo(*storage_info);
112 *location = GetDeviceLocationFromStorageName(storage_name);
115 } // namespace
117 MediaTransferProtocolDeviceObserverLinux::
118 MediaTransferProtocolDeviceObserverLinux(
119 StorageMonitor::Receiver* receiver,
120 device::MediaTransferProtocolManager* mtp_manager)
121 : mtp_manager_(mtp_manager),
122 get_storage_info_func_(&GetStorageInfo),
123 notifications_(receiver) {
124 mtp_manager_->AddObserver(this);
125 EnumerateStorages();
128 // This constructor is only used by unit tests.
129 MediaTransferProtocolDeviceObserverLinux::
130 MediaTransferProtocolDeviceObserverLinux(
131 StorageMonitor::Receiver* receiver,
132 device::MediaTransferProtocolManager* mtp_manager,
133 GetStorageInfoFunc get_storage_info_func)
134 : mtp_manager_(mtp_manager),
135 get_storage_info_func_(get_storage_info_func),
136 notifications_(receiver) {
139 MediaTransferProtocolDeviceObserverLinux::
140 ~MediaTransferProtocolDeviceObserverLinux() {
141 mtp_manager_->RemoveObserver(this);
144 bool MediaTransferProtocolDeviceObserverLinux::GetStorageInfoForPath(
145 const base::FilePath& path,
146 StorageInfo* storage_info) const {
147 DCHECK(storage_info);
149 if (!path.IsAbsolute())
150 return false;
152 std::vector<base::FilePath::StringType> path_components;
153 path.GetComponents(&path_components);
154 if (path_components.size() < 2)
155 return false;
157 // First and second component of the path specifies the device location.
158 // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the
159 // device location.
160 StorageLocationToInfoMap::const_iterator info_it =
161 storage_map_.find(GetDeviceLocationFromStorageName(path_components[1]));
162 if (info_it == storage_map_.end())
163 return false;
165 *storage_info = info_it->second;
166 return true;
169 void MediaTransferProtocolDeviceObserverLinux::EjectDevice(
170 const std::string& device_id,
171 base::Callback<void(StorageMonitor::EjectStatus)> callback) {
172 std::string location;
173 if (!GetLocationForDeviceId(device_id, &location)) {
174 callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE);
175 return;
178 // TODO(thestig): Change this to tell the mtp manager to eject the device.
180 StorageChanged(false, location);
181 callback.Run(StorageMonitor::EJECT_OK);
184 // device::MediaTransferProtocolManager::Observer override.
185 void MediaTransferProtocolDeviceObserverLinux::StorageChanged(
186 bool is_attached,
187 const std::string& storage_name) {
188 DCHECK(!storage_name.empty());
190 // New storage is attached.
191 if (is_attached) {
192 std::string device_id;
193 base::string16 storage_label;
194 std::string location;
195 get_storage_info_func_(storage_name, mtp_manager_,
196 &device_id, &storage_label, &location);
198 // Keep track of device id and device name to see how often we receive
199 // empty values.
200 MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id,
201 storage_label);
202 if (device_id.empty() || storage_label.empty())
203 return;
205 DCHECK(!ContainsKey(storage_map_, location));
207 StorageInfo storage_info(device_id, location, storage_label,
208 base::string16(), base::string16(), 0);
209 storage_map_[location] = storage_info;
210 notifications_->ProcessAttach(storage_info);
211 } else {
212 // Existing storage is detached.
213 StorageLocationToInfoMap::iterator it =
214 storage_map_.find(GetDeviceLocationFromStorageName(storage_name));
215 if (it == storage_map_.end())
216 return;
217 notifications_->ProcessDetach(it->second.device_id());
218 storage_map_.erase(it);
222 void MediaTransferProtocolDeviceObserverLinux::EnumerateStorages() {
223 typedef std::vector<std::string> StorageList;
224 StorageList storages = mtp_manager_->GetStorages();
225 for (StorageList::const_iterator storage_iter = storages.begin();
226 storage_iter != storages.end(); ++storage_iter) {
227 StorageChanged(true, *storage_iter);
231 bool MediaTransferProtocolDeviceObserverLinux::GetLocationForDeviceId(
232 const std::string& device_id, std::string* location) const {
233 for (StorageLocationToInfoMap::const_iterator it = storage_map_.begin();
234 it != storage_map_.end(); ++it) {
235 if (it->second.device_id() == device_id) {
236 *location = it->first;
237 return true;
241 return false;
244 } // namespace storage_monitor