Rename GetIconID to GetIconId
[chromium-blink-merge.git] / components / storage_monitor / storage_monitor_chromeos.cc
blobbc1d7c58ba91308691813118f0eabc5adec01f57
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/storage_monitor_chromeos.h"
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/storage_monitor/media_storage_util.h"
16 #include "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
17 #include "components/storage_monitor/removable_device_constants.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
21 using chromeos::disks::DiskMountManager;
23 namespace storage_monitor {
25 namespace {
27 // Constructs a device id using uuid or manufacturer (vendor and product) id
28 // details.
29 std::string MakeDeviceUniqueId(const DiskMountManager::Disk& disk) {
30 std::string uuid = disk.fs_uuid();
31 if (!uuid.empty())
32 return kFSUniqueIdPrefix + uuid;
34 // If one of the vendor or product information is missing, its value in the
35 // string is empty.
36 // Format: VendorModelSerial:VendorInfo:ModelInfo:SerialInfo
37 // TODO(kmadhusu) Extract serial information for the disks and append it to
38 // the device unique id.
39 const std::string& vendor = disk.vendor_id();
40 const std::string& product = disk.product_id();
41 if (vendor.empty() && product.empty())
42 return std::string();
43 return kVendorModelSerialPrefix + vendor + ":" + product + ":";
46 // Returns true if the requested device is valid, else false. On success, fills
47 // in |info|.
48 bool GetDeviceInfo(const DiskMountManager::MountPointInfo& mount_info,
49 bool has_dcim,
50 StorageInfo* info) {
51 DCHECK(info);
52 std::string source_path = mount_info.source_path;
54 const DiskMountManager::Disk* disk =
55 DiskMountManager::GetInstance()->FindDiskBySourcePath(source_path);
56 if (!disk || disk->device_type() == chromeos::DEVICE_TYPE_UNKNOWN)
57 return false;
59 std::string unique_id = MakeDeviceUniqueId(*disk);
60 // Keep track of device uuid and label, to see how often we receive empty
61 // values.
62 base::string16 device_label = base::UTF8ToUTF16(disk->device_label());
63 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, device_label);
64 if (unique_id.empty())
65 return false;
67 StorageInfo::Type type = has_dcim ?
68 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM :
69 StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
71 *info = StorageInfo(StorageInfo::MakeDeviceId(type, unique_id),
72 mount_info.mount_path,
73 device_label,
74 base::UTF8ToUTF16(disk->vendor_name()),
75 base::UTF8ToUTF16(disk->product_name()),
76 disk->total_size_in_bytes());
77 return true;
80 // Returns whether the mount point in |mount_info| is a media device or not.
81 bool CheckMountedPathOnFileThread(
82 const DiskMountManager::MountPointInfo& mount_info) {
83 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
84 return MediaStorageUtil::HasDcim(base::FilePath(mount_info.mount_path));
87 } // namespace
89 using content::BrowserThread;
91 StorageMonitorCros::StorageMonitorCros()
92 : weak_ptr_factory_(this) {
95 StorageMonitorCros::~StorageMonitorCros() {
96 DiskMountManager* manager = DiskMountManager::GetInstance();
97 if (manager) {
98 manager->RemoveObserver(this);
102 void StorageMonitorCros::Init() {
103 DCHECK(DiskMountManager::GetInstance());
104 DiskMountManager::GetInstance()->AddObserver(this);
105 CheckExistingMountPoints();
107 if (!media_transfer_protocol_manager_) {
108 media_transfer_protocol_manager_.reset(
109 device::MediaTransferProtocolManager::Initialize(
110 scoped_refptr<base::SingleThreadTaskRunner>()));
113 media_transfer_protocol_device_observer_.reset(
114 new MediaTransferProtocolDeviceObserverLinux(
115 receiver(), media_transfer_protocol_manager_.get()));
118 void StorageMonitorCros::CheckExistingMountPoints() {
119 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
120 const DiskMountManager::MountPointMap& mount_point_map =
121 DiskMountManager::GetInstance()->mount_points();
122 for (DiskMountManager::MountPointMap::const_iterator it =
123 mount_point_map.begin(); it != mount_point_map.end(); ++it) {
124 BrowserThread::PostTaskAndReplyWithResult(
125 BrowserThread::FILE, FROM_HERE,
126 base::Bind(&CheckMountedPathOnFileThread, it->second),
127 base::Bind(&StorageMonitorCros::AddMountedPath,
128 weak_ptr_factory_.GetWeakPtr(), it->second));
131 // Note: relies on scheduled tasks on the file thread being sequential. This
132 // block needs to follow the for loop, so that the DoNothing call on the FILE
133 // thread happens after the scheduled metadata retrievals, meaning that the
134 // reply callback will then happen after all the AddNewMount calls.
135 BrowserThread::PostTaskAndReply(
136 BrowserThread::FILE, FROM_HERE,
137 base::Bind(&base::DoNothing),
138 base::Bind(&StorageMonitorCros::MarkInitialized,
139 weak_ptr_factory_.GetWeakPtr()));
142 void StorageMonitorCros::OnDiskEvent(DiskMountManager::DiskEvent event,
143 const DiskMountManager::Disk* disk) {}
145 void StorageMonitorCros::OnDeviceEvent(DiskMountManager::DeviceEvent event,
146 const std::string& device_path) {}
148 void StorageMonitorCros::OnMountEvent(
149 DiskMountManager::MountEvent event,
150 chromeos::MountError error_code,
151 const DiskMountManager::MountPointInfo& mount_info) {
152 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
154 // Ignore mount points that are not devices.
155 if (mount_info.mount_type != chromeos::MOUNT_TYPE_DEVICE)
156 return;
157 // Ignore errors.
158 if (error_code != chromeos::MOUNT_ERROR_NONE)
159 return;
160 if (mount_info.mount_condition != chromeos::disks::MOUNT_CONDITION_NONE)
161 return;
163 switch (event) {
164 case DiskMountManager::MOUNTING: {
165 if (ContainsKey(mount_map_, mount_info.mount_path)) {
166 NOTREACHED();
167 return;
170 BrowserThread::PostTaskAndReplyWithResult(
171 BrowserThread::FILE, FROM_HERE,
172 base::Bind(&CheckMountedPathOnFileThread, mount_info),
173 base::Bind(&StorageMonitorCros::AddMountedPath,
174 weak_ptr_factory_.GetWeakPtr(), mount_info));
175 break;
177 case DiskMountManager::UNMOUNTING: {
178 MountMap::iterator it = mount_map_.find(mount_info.mount_path);
179 if (it == mount_map_.end())
180 return;
181 receiver()->ProcessDetach(it->second.device_id());
182 mount_map_.erase(it);
183 break;
188 void StorageMonitorCros::OnFormatEvent(DiskMountManager::FormatEvent event,
189 chromeos::FormatError error_code,
190 const std::string& device_path) {}
192 void StorageMonitorCros::SetMediaTransferProtocolManagerForTest(
193 device::MediaTransferProtocolManager* test_manager) {
194 DCHECK(!media_transfer_protocol_manager_);
195 media_transfer_protocol_manager_.reset(test_manager);
199 bool StorageMonitorCros::GetStorageInfoForPath(
200 const base::FilePath& path,
201 StorageInfo* device_info) const {
202 DCHECK(device_info);
204 if (media_transfer_protocol_device_observer_->GetStorageInfoForPath(
205 path, device_info)) {
206 return true;
209 if (!path.IsAbsolute())
210 return false;
212 base::FilePath current = path;
213 while (!ContainsKey(mount_map_, current.value()) &&
214 current != current.DirName()) {
215 current = current.DirName();
218 MountMap::const_iterator info_it = mount_map_.find(current.value());
219 if (info_it == mount_map_.end())
220 return false;
222 *device_info = info_it->second;
223 return true;
226 // Callback executed when the unmount call is run by DiskMountManager.
227 // Forwards result to |EjectDevice| caller.
228 void NotifyUnmountResult(
229 base::Callback<void(StorageMonitor::EjectStatus)> callback,
230 chromeos::MountError error_code) {
231 if (error_code == chromeos::MOUNT_ERROR_NONE)
232 callback.Run(StorageMonitor::EJECT_OK);
233 else
234 callback.Run(StorageMonitor::EJECT_FAILURE);
237 void StorageMonitorCros::EjectDevice(
238 const std::string& device_id,
239 base::Callback<void(EjectStatus)> callback) {
240 StorageInfo::Type type;
241 if (!StorageInfo::CrackDeviceId(device_id, &type, NULL)) {
242 callback.Run(EJECT_FAILURE);
243 return;
246 if (type == StorageInfo::MTP_OR_PTP) {
247 media_transfer_protocol_device_observer_->EjectDevice(device_id, callback);
248 return;
251 std::string mount_path;
252 for (MountMap::const_iterator info_it = mount_map_.begin();
253 info_it != mount_map_.end(); ++info_it) {
254 if (info_it->second.device_id() == device_id)
255 mount_path = info_it->first;
258 if (mount_path.empty()) {
259 callback.Run(EJECT_NO_SUCH_DEVICE);
260 return;
263 DiskMountManager* manager = DiskMountManager::GetInstance();
264 if (!manager) {
265 callback.Run(EJECT_FAILURE);
266 return;
269 manager->UnmountPath(mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
270 base::Bind(NotifyUnmountResult, callback));
273 device::MediaTransferProtocolManager*
274 StorageMonitorCros::media_transfer_protocol_manager() {
275 return media_transfer_protocol_manager_.get();
278 void StorageMonitorCros::AddMountedPath(
279 const DiskMountManager::MountPointInfo& mount_info,
280 bool has_dcim) {
281 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
283 if (ContainsKey(mount_map_, mount_info.mount_path)) {
284 // CheckExistingMountPointsOnUIThread() added the mount point information
285 // in the map before the device attached handler is called. Therefore, an
286 // entry for the device already exists in the map.
287 return;
290 // Get the media device uuid and label if exists.
291 StorageInfo info;
292 if (!GetDeviceInfo(mount_info, has_dcim, &info))
293 return;
295 if (info.device_id().empty())
296 return;
298 mount_map_.insert(std::make_pair(mount_info.mount_path, info));
300 receiver()->ProcessAttach(info);
303 StorageMonitor* StorageMonitor::CreateInternal() {
304 return new StorageMonitorCros();
307 } // namespace storage_monitor