Fix build break
[chromium-blink-merge.git] / chrome / browser / storage_monitor / storage_monitor_chromeos.cc
blobbd8e091d16770fec2102ac70737148995dbec793
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/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/stl_util.h"
13 #include "base/string_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/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 "chrome/common/chrome_switches.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
23 namespace chromeos {
25 namespace {
27 // Constructs a device name using label or manufacturer (vendor and product)
28 // name details.
29 string16 GetDeviceName(const disks::DiskMountManager::Disk& disk,
30 string16* storage_label,
31 string16* vendor_name,
32 string16* model_name) {
33 if (disk.device_type() == DEVICE_TYPE_SD) {
34 // Mount path of an SD card will be one of the following:
35 // (1) /media/removable/<volume_label>
36 // (2) /media/removable/SD Card
37 // If the volume label is available, mount path will be (1) else (2).
38 base::FilePath mount_point(disk.mount_path());
39 const string16 display_name(mount_point.BaseName().LossyDisplayName());
40 if (!display_name.empty())
41 return display_name;
44 const std::string& device_label = disk.device_label();
46 if (storage_label)
47 *storage_label = UTF8ToUTF16(device_label);
48 if (vendor_name)
49 *vendor_name = UTF8ToUTF16(disk.vendor_name());
50 if (model_name)
51 *model_name = UTF8ToUTF16(disk.product_name());
53 if (!device_label.empty() && IsStringUTF8(device_label))
54 return UTF8ToUTF16(device_label);
56 return chrome::MediaStorageUtil::GetFullProductName(disk.vendor_name(),
57 disk.product_name());
60 // Constructs a device id using uuid or manufacturer (vendor and product) id
61 // details.
62 std::string MakeDeviceUniqueId(const disks::DiskMountManager::Disk& disk) {
63 std::string uuid = disk.fs_uuid();
64 if (!uuid.empty())
65 return chrome::kFSUniqueIdPrefix + uuid;
67 // If one of the vendor or product information is missing, its value in the
68 // string is empty.
69 // Format: VendorModelSerial:VendorInfo:ModelInfo:SerialInfo
70 // TODO(kmadhusu) Extract serial information for the disks and append it to
71 // the device unique id.
72 const std::string& vendor = disk.vendor_id();
73 const std::string& product = disk.product_id();
74 if (vendor.empty() && product.empty())
75 return std::string();
76 return chrome::kVendorModelSerialPrefix + vendor + ":" + product + ":";
79 // Returns true if the requested device is valid, else false. On success, fills
80 // in |unique_id|, |device_label| and |storage_size_in_bytes|.
81 bool GetDeviceInfo(const std::string& source_path,
82 std::string* unique_id,
83 string16* device_label,
84 uint64* storage_size_in_bytes,
85 string16* storage_label,
86 string16* vendor_name,
87 string16* model_name) {
88 const disks::DiskMountManager::Disk* disk =
89 disks::DiskMountManager::GetInstance()->FindDiskBySourcePath(source_path);
90 if (!disk || disk->device_type() == DEVICE_TYPE_UNKNOWN)
91 return false;
93 if (unique_id)
94 *unique_id = MakeDeviceUniqueId(*disk);
96 if (device_label)
97 *device_label = GetDeviceName(*disk, storage_label,
98 vendor_name, model_name);
100 if (storage_size_in_bytes)
101 *storage_size_in_bytes = disk->total_size_in_bytes();
102 return true;
105 // Returns whether the mount point in |mount_info| is a media device or not.
106 bool CheckMountedPathOnFileThread(
107 const disks::DiskMountManager::MountPointInfo& mount_info) {
108 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
109 return chrome::MediaStorageUtil::HasDcim(
110 base::FilePath(mount_info.mount_path));
113 } // namespace
115 using content::BrowserThread;
116 using chrome::StorageInfo;
118 StorageMonitorCros::StorageMonitorCros()
119 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
122 StorageMonitorCros::~StorageMonitorCros() {
123 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
124 device::MediaTransferProtocolManager::Shutdown();
127 disks::DiskMountManager* manager = disks::DiskMountManager::GetInstance();
128 if (manager) {
129 manager->RemoveObserver(this);
133 void StorageMonitorCros::Init() {
134 DCHECK(disks::DiskMountManager::GetInstance());
135 disks::DiskMountManager::GetInstance()->AddObserver(this);
136 CheckExistingMountPoints();
138 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
139 scoped_refptr<base::MessageLoopProxy> loop_proxy;
140 device::MediaTransferProtocolManager::Initialize(loop_proxy);
142 media_transfer_protocol_device_observer_.reset(
143 new chrome::MediaTransferProtocolDeviceObserverLinux(receiver()));
147 void StorageMonitorCros::CheckExistingMountPoints() {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149 const disks::DiskMountManager::MountPointMap& mount_point_map =
150 disks::DiskMountManager::GetInstance()->mount_points();
151 for (disks::DiskMountManager::MountPointMap::const_iterator it =
152 mount_point_map.begin(); it != mount_point_map.end(); ++it) {
153 BrowserThread::PostTaskAndReplyWithResult(
154 BrowserThread::FILE, FROM_HERE,
155 base::Bind(&CheckMountedPathOnFileThread, it->second),
156 base::Bind(&StorageMonitorCros::AddMountedPath,
157 weak_ptr_factory_.GetWeakPtr(), it->second));
161 void StorageMonitorCros::OnDiskEvent(
162 disks::DiskMountManager::DiskEvent event,
163 const disks::DiskMountManager::Disk* disk) {
166 void StorageMonitorCros::OnDeviceEvent(
167 disks::DiskMountManager::DeviceEvent event,
168 const std::string& device_path) {
171 void StorageMonitorCros::OnMountEvent(
172 disks::DiskMountManager::MountEvent event,
173 MountError error_code,
174 const disks::DiskMountManager::MountPointInfo& mount_info) {
175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177 // Ignore mount points that are not devices.
178 if (mount_info.mount_type != MOUNT_TYPE_DEVICE)
179 return;
180 // Ignore errors.
181 if (error_code != MOUNT_ERROR_NONE)
182 return;
183 if (mount_info.mount_condition != disks::MOUNT_CONDITION_NONE)
184 return;
186 switch (event) {
187 case disks::DiskMountManager::MOUNTING: {
188 if (ContainsKey(mount_map_, mount_info.mount_path)) {
189 NOTREACHED();
190 return;
193 BrowserThread::PostTaskAndReplyWithResult(
194 BrowserThread::FILE, FROM_HERE,
195 base::Bind(&CheckMountedPathOnFileThread, mount_info),
196 base::Bind(&StorageMonitorCros::AddMountedPath,
197 weak_ptr_factory_.GetWeakPtr(), mount_info));
198 break;
200 case disks::DiskMountManager::UNMOUNTING: {
201 MountMap::iterator it = mount_map_.find(mount_info.mount_path);
202 if (it == mount_map_.end())
203 return;
204 receiver()->ProcessDetach(it->second.device_id);
205 mount_map_.erase(it);
206 break;
211 void StorageMonitorCros::OnFormatEvent(
212 disks::DiskMountManager::FormatEvent event,
213 FormatError error_code,
214 const std::string& device_path) {
217 bool StorageMonitorCros::GetStorageInfoForPath(
218 const base::FilePath& path,
219 StorageInfo* device_info) const {
220 // TODO(thestig) |media_transfer_protocol_device_observer_| should always be
221 // valid.
222 if (media_transfer_protocol_device_observer_ &&
223 media_transfer_protocol_device_observer_->GetStorageInfoForPath(
224 path, device_info)) {
225 return true;
228 if (!path.IsAbsolute())
229 return false;
231 base::FilePath current = path;
232 while (!ContainsKey(mount_map_, current.value()) &&
233 current != current.DirName()) {
234 current = current.DirName();
237 MountMap::const_iterator info_it = mount_map_.find(current.value());
238 if (info_it == mount_map_.end())
239 return false;
241 if (device_info)
242 *device_info = info_it->second;
243 return true;
246 // Callback executed when the unmount call is run by DiskMountManager.
247 // Forwards result to |EjectDevice| caller.
248 void NotifyUnmountResult(
249 base::Callback<void(chrome::StorageMonitor::EjectStatus)> callback,
250 chromeos::MountError error_code) {
251 if (error_code == MOUNT_ERROR_NONE)
252 callback.Run(chrome::StorageMonitor::EJECT_OK);
253 else
254 callback.Run(chrome::StorageMonitor::EJECT_FAILURE);
257 void StorageMonitorCros::EjectDevice(
258 const std::string& device_id,
259 base::Callback<void(EjectStatus)> callback) {
260 std::string mount_path;
261 for (MountMap::const_iterator info_it = mount_map_.begin();
262 info_it != mount_map_.end(); ++info_it) {
263 if (info_it->second.device_id == device_id)
264 mount_path = info_it->first;
267 if (mount_path.empty()) {
268 callback.Run(EJECT_NO_SUCH_DEVICE);
269 return;
272 disks::DiskMountManager* manager = disks::DiskMountManager::GetInstance();
273 if (!manager) {
274 callback.Run(EJECT_FAILURE);
275 return;
278 manager->UnmountPath(mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
279 base::Bind(NotifyUnmountResult, callback));
282 void StorageMonitorCros::AddMountedPath(
283 const disks::DiskMountManager::MountPointInfo& mount_info, bool has_dcim) {
284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286 if (ContainsKey(mount_map_, mount_info.mount_path)) {
287 // CheckExistingMountPointsOnUIThread() added the mount point information
288 // in the map before the device attached handler is called. Therefore, an
289 // entry for the device already exists in the map.
290 return;
293 // Get the media device uuid and label if exists.
294 std::string unique_id;
295 string16 device_label;
296 string16 storage_label;
297 string16 vendor_name;
298 string16 model_name;
299 uint64 storage_size_in_bytes;
300 if (!GetDeviceInfo(mount_info.source_path, &unique_id, &device_label,
301 &storage_size_in_bytes, &storage_label,
302 &vendor_name, &model_name))
303 return;
305 // Keep track of device uuid and label, to see how often we receive empty
306 // values.
307 chrome::MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id,
308 device_label);
309 if (unique_id.empty() || device_label.empty())
310 return;
312 chrome::MediaStorageUtil::Type type = has_dcim ?
313 chrome::MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM :
314 chrome::MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
316 std::string device_id = chrome::MediaStorageUtil::MakeDeviceId(type,
317 unique_id);
319 chrome::StorageInfo object_info(
320 device_id,
321 chrome::MediaStorageUtil::GetDisplayNameForDevice(storage_size_in_bytes,
322 device_label),
323 mount_info.mount_path,
324 storage_label,
325 vendor_name,
326 model_name,
327 storage_size_in_bytes);
329 mount_map_.insert(std::make_pair(mount_info.mount_path, object_info));
331 receiver()->ProcessAttach(object_info);
334 } // namespace chromeos