Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / storage_monitor / storage_monitor_chromeos.cc
blob6b090c39f976c03a2f5a02163a480acc7ec2b690
1 // Copyright (c) 2012 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 // chromeos::StorageMonitorCros implementation.
7 #include "chrome/browser/storage_monitor/storage_monitor_chromeos.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/storage_monitor/media_storage_util.h"
17 #include "chrome/browser/storage_monitor/media_transfer_protocol_device_observer_linux.h"
18 #include "chrome/browser/storage_monitor/removable_device_constants.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
22 namespace chromeos {
24 namespace {
26 // Constructs a device id using uuid or manufacturer (vendor and product) id
27 // details.
28 std::string MakeDeviceUniqueId(const disks::DiskMountManager::Disk& disk) {
29 std::string uuid = disk.fs_uuid();
30 if (!uuid.empty())
31 return kFSUniqueIdPrefix + uuid;
33 // If one of the vendor or product information is missing, its value in the
34 // string is empty.
35 // Format: VendorModelSerial:VendorInfo:ModelInfo:SerialInfo
36 // TODO(kmadhusu) Extract serial information for the disks and append it to
37 // the device unique id.
38 const std::string& vendor = disk.vendor_id();
39 const std::string& product = disk.product_id();
40 if (vendor.empty() && product.empty())
41 return std::string();
42 return kVendorModelSerialPrefix + vendor + ":" + product + ":";
45 // Returns true if the requested device is valid, else false. On success, fills
46 // in |info|.
47 bool GetDeviceInfo(const disks::DiskMountManager::MountPointInfo& mount_info,
48 bool has_dcim,
49 StorageInfo* info) {
50 DCHECK(info);
51 std::string source_path = mount_info.source_path;
53 const disks::DiskMountManager::Disk* disk =
54 disks::DiskMountManager::GetInstance()->FindDiskBySourcePath(source_path);
55 if (!disk || disk->device_type() == DEVICE_TYPE_UNKNOWN)
56 return false;
58 std::string unique_id = MakeDeviceUniqueId(*disk);
59 // Keep track of device uuid and label, to see how often we receive empty
60 // values.
61 base::string16 device_label = base::UTF8ToUTF16(disk->device_label());
62 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, device_label);
63 if (unique_id.empty())
64 return false;
66 StorageInfo::Type type = has_dcim ?
67 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM :
68 StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
70 *info = StorageInfo(StorageInfo::MakeDeviceId(type, unique_id),
71 base::string16(),
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 disks::DiskMountManager::MountPointInfo& mount_info) {
83 DCHECK(content::BrowserThread::CurrentlyOn(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 disks::DiskMountManager* manager = disks::DiskMountManager::GetInstance();
97 if (manager) {
98 manager->RemoveObserver(this);
102 void StorageMonitorCros::Init() {
103 DCHECK(disks::DiskMountManager::GetInstance());
104 disks::DiskMountManager::GetInstance()->AddObserver(this);
105 CheckExistingMountPoints();
107 if (!media_transfer_protocol_manager_) {
108 scoped_refptr<base::MessageLoopProxy> loop_proxy;
109 media_transfer_protocol_manager_.reset(
110 device::MediaTransferProtocolManager::Initialize(loop_proxy));
113 media_transfer_protocol_device_observer_.reset(
114 new MediaTransferProtocolDeviceObserverLinux(
115 receiver(), media_transfer_protocol_manager_.get()));
118 void StorageMonitorCros::CheckExistingMountPoints() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120 const disks::DiskMountManager::MountPointMap& mount_point_map =
121 disks::DiskMountManager::GetInstance()->mount_points();
122 for (disks::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(
143 disks::DiskMountManager::DiskEvent event,
144 const disks::DiskMountManager::Disk* disk) {
147 void StorageMonitorCros::OnDeviceEvent(
148 disks::DiskMountManager::DeviceEvent event,
149 const std::string& device_path) {
152 void StorageMonitorCros::OnMountEvent(
153 disks::DiskMountManager::MountEvent event,
154 MountError error_code,
155 const disks::DiskMountManager::MountPointInfo& mount_info) {
156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158 // Ignore mount points that are not devices.
159 if (mount_info.mount_type != MOUNT_TYPE_DEVICE)
160 return;
161 // Ignore errors.
162 if (error_code != MOUNT_ERROR_NONE)
163 return;
164 if (mount_info.mount_condition != disks::MOUNT_CONDITION_NONE)
165 return;
167 switch (event) {
168 case disks::DiskMountManager::MOUNTING: {
169 if (ContainsKey(mount_map_, mount_info.mount_path)) {
170 NOTREACHED();
171 return;
174 BrowserThread::PostTaskAndReplyWithResult(
175 BrowserThread::FILE, FROM_HERE,
176 base::Bind(&CheckMountedPathOnFileThread, mount_info),
177 base::Bind(&StorageMonitorCros::AddMountedPath,
178 weak_ptr_factory_.GetWeakPtr(), mount_info));
179 break;
181 case disks::DiskMountManager::UNMOUNTING: {
182 MountMap::iterator it = mount_map_.find(mount_info.mount_path);
183 if (it == mount_map_.end())
184 return;
185 receiver()->ProcessDetach(it->second.device_id());
186 mount_map_.erase(it);
187 break;
192 void StorageMonitorCros::OnFormatEvent(
193 disks::DiskMountManager::FormatEvent event,
194 FormatError error_code,
195 const std::string& device_path) {
198 void StorageMonitorCros::SetMediaTransferProtocolManagerForTest(
199 device::MediaTransferProtocolManager* test_manager) {
200 DCHECK(!media_transfer_protocol_manager_);
201 media_transfer_protocol_manager_.reset(test_manager);
205 bool StorageMonitorCros::GetStorageInfoForPath(
206 const base::FilePath& path,
207 StorageInfo* device_info) const {
208 DCHECK(device_info);
210 if (media_transfer_protocol_device_observer_->GetStorageInfoForPath(
211 path, device_info)) {
212 return true;
215 if (!path.IsAbsolute())
216 return false;
218 base::FilePath current = path;
219 while (!ContainsKey(mount_map_, current.value()) &&
220 current != current.DirName()) {
221 current = current.DirName();
224 MountMap::const_iterator info_it = mount_map_.find(current.value());
225 if (info_it == mount_map_.end())
226 return false;
228 *device_info = info_it->second;
229 return true;
232 // Callback executed when the unmount call is run by DiskMountManager.
233 // Forwards result to |EjectDevice| caller.
234 void NotifyUnmountResult(
235 base::Callback<void(StorageMonitor::EjectStatus)> callback,
236 chromeos::MountError error_code) {
237 if (error_code == MOUNT_ERROR_NONE)
238 callback.Run(StorageMonitor::EJECT_OK);
239 else
240 callback.Run(StorageMonitor::EJECT_FAILURE);
243 void StorageMonitorCros::EjectDevice(
244 const std::string& device_id,
245 base::Callback<void(EjectStatus)> callback) {
246 StorageInfo::Type type;
247 if (!StorageInfo::CrackDeviceId(device_id, &type, NULL)) {
248 callback.Run(EJECT_FAILURE);
249 return;
252 if (type == StorageInfo::MTP_OR_PTP) {
253 media_transfer_protocol_device_observer_->EjectDevice(device_id, callback);
254 return;
257 std::string mount_path;
258 for (MountMap::const_iterator info_it = mount_map_.begin();
259 info_it != mount_map_.end(); ++info_it) {
260 if (info_it->second.device_id() == device_id)
261 mount_path = info_it->first;
264 if (mount_path.empty()) {
265 callback.Run(EJECT_NO_SUCH_DEVICE);
266 return;
269 disks::DiskMountManager* manager = disks::DiskMountManager::GetInstance();
270 if (!manager) {
271 callback.Run(EJECT_FAILURE);
272 return;
275 manager->UnmountPath(mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
276 base::Bind(NotifyUnmountResult, callback));
279 device::MediaTransferProtocolManager*
280 StorageMonitorCros::media_transfer_protocol_manager() {
281 return media_transfer_protocol_manager_.get();
284 void StorageMonitorCros::AddMountedPath(
285 const disks::DiskMountManager::MountPointInfo& mount_info, bool has_dcim) {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 if (ContainsKey(mount_map_, mount_info.mount_path)) {
289 // CheckExistingMountPointsOnUIThread() added the mount point information
290 // in the map before the device attached handler is called. Therefore, an
291 // entry for the device already exists in the map.
292 return;
295 // Get the media device uuid and label if exists.
296 StorageInfo info;
297 if (!GetDeviceInfo(mount_info, has_dcim, &info))
298 return;
300 if (info.device_id().empty())
301 return;
303 mount_map_.insert(std::make_pair(mount_info.mount_path, info));
305 receiver()->ProcessAttach(info);
308 } // namespace chromeos
310 StorageMonitor* StorageMonitor::Create() {
311 return new chromeos::StorageMonitorCros();