Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / chromeos / file_manager / volume_manager.cc
blob915ca1838499b985db296fdb6249fee5b4db89e7
1 // Copyright 2013 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 "chrome/browser/chromeos/file_manager/volume_manager.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
17 #include "chrome/browser/chromeos/drive/file_errors.h"
18 #include "chrome/browser/chromeos/drive/file_system_interface.h"
19 #include "chrome/browser/chromeos/drive/file_system_util.h"
20 #include "chrome/browser/chromeos/file_manager/mounted_disk_monitor.h"
21 #include "chrome/browser/chromeos/file_manager/path_util.h"
22 #include "chrome/browser/chromeos/file_manager/volume_manager_factory.h"
23 #include "chrome/browser/chromeos/file_manager/volume_manager_observer.h"
24 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
25 #include "chrome/browser/chromeos/profiles/profile_helper.h"
26 #include "chrome/browser/local_discovery/storage/privet_filesystem_constants.h"
27 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
31 #include "chromeos/chromeos_switches.h"
32 #include "chromeos/dbus/cros_disks_client.h"
33 #include "chromeos/disks/disk_mount_manager.h"
34 #include "components/storage_monitor/storage_monitor.h"
35 #include "content/public/browser/browser_context.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "webkit/browser/fileapi/external_mount_points.h"
39 namespace file_manager {
40 namespace {
42 // A named constant to be passed to the |is_remounting| parameter.
43 const bool kNotRemounting = false;
45 const char kFileManagerMTPMountNamePrefix[] = "fileman-mtp-";
47 // Registers |path| as the "Downloads" folder to the FileSystem API backend.
48 // If another folder is already mounted. It revokes and overrides the old one.
49 bool RegisterDownloadsMountPoint(Profile* profile, const base::FilePath& path) {
50 // Although we show only profile's own "Downloads" folder in Files.app,
51 // in the backend we need to mount all profile's download directory globally.
52 // Otherwise, Files.app cannot support cross-profile file copies, etc.
53 // For this reason, we need to register to the global GetSystemInstance().
54 const std::string mount_point_name =
55 file_manager::util::GetDownloadsMountPointName(profile);
56 fileapi::ExternalMountPoints* const mount_points =
57 fileapi::ExternalMountPoints::GetSystemInstance();
59 // In some tests we want to override existing Downloads mount point, so we
60 // first revoke the existing mount point (if any).
61 mount_points->RevokeFileSystem(mount_point_name);
62 return mount_points->RegisterFileSystem(
63 mount_point_name, fileapi::kFileSystemTypeNativeLocal,
64 fileapi::FileSystemMountOption(), path);
67 // Finds the path register as the "Downloads" folder to FileSystem API backend.
68 // Returns false if it is not registered.
69 bool FindDownloadsMountPointPath(Profile* profile, base::FilePath* path) {
70 const std::string mount_point_name =
71 util::GetDownloadsMountPointName(profile);
72 fileapi::ExternalMountPoints* const mount_points =
73 fileapi::ExternalMountPoints::GetSystemInstance();
75 return mount_points->GetRegisteredPath(mount_point_name, path);
78 VolumeType MountTypeToVolumeType(chromeos::MountType type) {
79 switch (type) {
80 case chromeos::MOUNT_TYPE_INVALID:
81 // We don't expect this value, but list here, so that when any value
82 // is added to the enum definition but this is not edited, the compiler
83 // warns it.
84 break;
85 case chromeos::MOUNT_TYPE_DEVICE:
86 return VOLUME_TYPE_REMOVABLE_DISK_PARTITION;
87 case chromeos::MOUNT_TYPE_ARCHIVE:
88 return VOLUME_TYPE_MOUNTED_ARCHIVE_FILE;
91 NOTREACHED();
92 return VOLUME_TYPE_DOWNLOADS_DIRECTORY;
95 // Returns a string representation of the given volume type.
96 std::string VolumeTypeToString(VolumeType type) {
97 switch (type) {
98 case VOLUME_TYPE_GOOGLE_DRIVE:
99 return "drive";
100 case VOLUME_TYPE_DOWNLOADS_DIRECTORY:
101 return "downloads";
102 case VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
103 return "removable";
104 case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE:
105 return "archive";
106 case VOLUME_TYPE_CLOUD_DEVICE:
107 return "cloud_device";
108 case VOLUME_TYPE_PROVIDED:
109 return "provided";
110 case VOLUME_TYPE_MTP:
111 return "mtp";
112 case VOLUME_TYPE_TESTING:
113 return "testing";
115 NOTREACHED();
116 return "";
119 // Generates a unique volume ID for the given volume info.
120 std::string GenerateVolumeId(const VolumeInfo& volume_info) {
121 // For the same volume type, base names are unique, as mount points are
122 // flat for the same volume type.
123 return (VolumeTypeToString(volume_info.type) + ":" +
124 volume_info.mount_path.BaseName().AsUTF8Unsafe());
127 // Returns the VolumeInfo for Drive file system.
128 VolumeInfo CreateDriveVolumeInfo(Profile* profile) {
129 const base::FilePath& drive_path =
130 drive::util::GetDriveMountPointPath(profile);
132 VolumeInfo volume_info;
133 volume_info.type = VOLUME_TYPE_GOOGLE_DRIVE;
134 volume_info.device_type = chromeos::DEVICE_TYPE_UNKNOWN;
135 volume_info.source_path = drive_path;
136 volume_info.mount_path = drive_path;
137 volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
138 volume_info.is_parent = false;
139 volume_info.is_read_only = false;
140 volume_info.volume_id = GenerateVolumeId(volume_info);
141 return volume_info;
144 VolumeInfo CreateDownloadsVolumeInfo(const base::FilePath& downloads_path) {
145 VolumeInfo volume_info;
146 volume_info.type = VOLUME_TYPE_DOWNLOADS_DIRECTORY;
147 volume_info.device_type = chromeos::DEVICE_TYPE_UNKNOWN;
148 // Keep source_path empty.
149 volume_info.mount_path = downloads_path;
150 volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
151 volume_info.is_parent = false;
152 volume_info.is_read_only = false;
153 volume_info.volume_id = GenerateVolumeId(volume_info);
154 return volume_info;
157 VolumeInfo CreateTestingVolumeInfo(const base::FilePath& path,
158 VolumeType volume_type,
159 chromeos::DeviceType device_type) {
160 VolumeInfo volume_info;
161 volume_info.type = volume_type;
162 volume_info.device_type = device_type;
163 // Keep source_path empty.
164 volume_info.mount_path = path;
165 volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
166 volume_info.is_parent = false;
167 volume_info.is_read_only = false;
168 volume_info.volume_id = GenerateVolumeId(volume_info);
169 return volume_info;
172 VolumeInfo CreateVolumeInfoFromMountPointInfo(
173 const chromeos::disks::DiskMountManager::MountPointInfo& mount_point,
174 const chromeos::disks::DiskMountManager::Disk* disk) {
175 VolumeInfo volume_info;
176 volume_info.type = MountTypeToVolumeType(mount_point.mount_type);
177 volume_info.source_path = base::FilePath(mount_point.source_path);
178 volume_info.mount_path = base::FilePath(mount_point.mount_path);
179 volume_info.mount_condition = mount_point.mount_condition;
180 if (disk) {
181 volume_info.device_type = disk->device_type();
182 volume_info.system_path_prefix =
183 base::FilePath(disk->system_path_prefix());
184 volume_info.drive_label = disk->drive_label();
185 volume_info.is_parent = disk->is_parent();
186 volume_info.is_read_only = disk->is_read_only();
187 } else {
188 volume_info.device_type = chromeos::DEVICE_TYPE_UNKNOWN;
189 volume_info.is_parent = false;
190 volume_info.is_read_only =
191 (mount_point.mount_type == chromeos::MOUNT_TYPE_ARCHIVE);
193 volume_info.volume_id = GenerateVolumeId(volume_info);
195 return volume_info;
198 VolumeInfo CreatePrivetVolumeInfo(
199 const local_discovery::PrivetVolumeLister::VolumeInfo& privet_volume_info) {
200 VolumeInfo volume_info;
201 volume_info.type = VOLUME_TYPE_CLOUD_DEVICE;
202 volume_info.mount_path = privet_volume_info.volume_path;
203 volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
204 volume_info.is_parent = true;
205 volume_info.is_read_only = true;
206 volume_info.volume_id = GenerateVolumeId(volume_info);
207 return volume_info;
210 VolumeInfo CreateProvidedFileSystemVolumeInfo(
211 const chromeos::file_system_provider::ProvidedFileSystemInfo&
212 file_system_info) {
213 VolumeInfo volume_info;
214 volume_info.type = VOLUME_TYPE_PROVIDED;
215 volume_info.mount_path = file_system_info.mount_path();
216 volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
217 volume_info.is_parent = true;
218 volume_info.is_read_only = true;
219 volume_info.volume_id = GenerateVolumeId(volume_info);
220 volume_info.file_system_id = file_system_info.file_system_id();
221 return volume_info;
224 std::string GetMountPointNameForMediaStorage(
225 const storage_monitor::StorageInfo& info) {
226 std::string name(kFileManagerMTPMountNamePrefix);
227 name += info.device_id();
228 return name;
231 } // namespace
233 VolumeInfo::VolumeInfo()
234 : file_system_id(0),
235 type(VOLUME_TYPE_GOOGLE_DRIVE),
236 mount_condition(chromeos::disks::MOUNT_CONDITION_NONE),
237 is_parent(false),
238 is_read_only(false) {}
240 VolumeInfo::~VolumeInfo() {
243 VolumeManager::VolumeManager(
244 Profile* profile,
245 drive::DriveIntegrationService* drive_integration_service,
246 chromeos::PowerManagerClient* power_manager_client,
247 chromeos::disks::DiskMountManager* disk_mount_manager,
248 chromeos::file_system_provider::Service* file_system_provider_service)
249 : profile_(profile),
250 drive_integration_service_(drive_integration_service),
251 disk_mount_manager_(disk_mount_manager),
252 mounted_disk_monitor_(
253 new MountedDiskMonitor(power_manager_client, disk_mount_manager)),
254 file_system_provider_service_(file_system_provider_service),
255 weak_ptr_factory_(this) {
256 DCHECK(disk_mount_manager);
259 VolumeManager::~VolumeManager() {
262 VolumeManager* VolumeManager::Get(content::BrowserContext* context) {
263 return VolumeManagerFactory::Get(context);
266 void VolumeManager::Initialize() {
267 // If in Sign in profile, then skip mounting and listening for mount events.
268 if (chromeos::ProfileHelper::IsSigninProfile(profile_))
269 return;
271 // Path to mount user folders have changed several times. We need to migrate
272 // the old preferences on paths to the new format when needed. For the detail,
273 // see the comments in file_manager::util::MigratePathFromOldFormat,
274 // Note: Preferences related to downloads are handled in download_prefs.cc.
275 // TODO(kinaba): Remove this after several rounds of releases.
276 const base::FilePath old_path =
277 profile_->GetPrefs()->GetFilePath(prefs::kSelectFileLastDirectory);
278 base::FilePath new_path;
279 if (!old_path.empty() &&
280 file_manager::util::MigratePathFromOldFormat(profile_,
281 old_path, &new_path)) {
282 profile_->GetPrefs()->SetFilePath(prefs::kSelectFileLastDirectory,
283 new_path);
286 // Register 'Downloads' folder for the profile to the file system.
287 const base::FilePath downloads =
288 file_manager::util::GetDownloadsFolderForProfile(profile_);
289 const bool success = RegisterDownloadsMountPoint(profile_, downloads);
290 DCHECK(success);
292 DoMountEvent(chromeos::MOUNT_ERROR_NONE,
293 CreateDownloadsVolumeInfo(downloads),
294 kNotRemounting);
296 // Subscribe to DriveIntegrationService.
297 if (drive_integration_service_) {
298 drive_integration_service_->AddObserver(this);
299 if (drive_integration_service_->IsMounted()) {
300 DoMountEvent(chromeos::MOUNT_ERROR_NONE,
301 CreateDriveVolumeInfo(profile_),
302 kNotRemounting);
306 // Subscribe to DiskMountManager.
307 disk_mount_manager_->AddObserver(this);
309 // Subscribe to FileSystemProviderService and register currently mounted
310 // volumes for the profile.
311 if (file_system_provider_service_) {
312 using chromeos::file_system_provider::ProvidedFileSystemInfo;
313 file_system_provider_service_->AddObserver(this);
315 std::vector<ProvidedFileSystemInfo> file_system_info_list =
316 file_system_provider_service_->GetProvidedFileSystemInfoList();
317 for (size_t i = 0; i < file_system_info_list.size(); ++i) {
318 VolumeInfo volume_info =
319 CreateProvidedFileSystemVolumeInfo(file_system_info_list[i]);
320 DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume_info, kNotRemounting);
324 std::vector<VolumeInfo> archives;
326 const chromeos::disks::DiskMountManager::MountPointMap& mount_points =
327 disk_mount_manager_->mount_points();
328 for (chromeos::disks::DiskMountManager::MountPointMap::const_iterator it =
329 mount_points.begin();
330 it != mount_points.end();
331 ++it) {
332 if (it->second.mount_type == chromeos::MOUNT_TYPE_ARCHIVE) {
333 // Archives are mounted after other type of volumes. See below.
334 archives.push_back(CreateVolumeInfoFromMountPointInfo(it->second, NULL));
335 continue;
337 DoMountEvent(
338 chromeos::MOUNT_ERROR_NONE,
339 CreateVolumeInfoFromMountPointInfo(
340 it->second,
341 disk_mount_manager_->FindDiskBySourcePath(it->second.source_path)),
342 kNotRemounting);
345 // We mount archives only if they are opened from currently mounted volumes.
346 // To check the condition correctly in DoMountEvent, we care the order.
347 std::vector<bool> done(archives.size(), false);
348 for (size_t i = 0; i < archives.size(); ++i) {
349 if (!done[i]) {
350 std::vector<VolumeInfo> chain;
351 done[i] = true;
352 chain.push_back(archives[i]);
354 // If archives[i]'s source_path is in another archive, mount it first.
355 for (size_t parent = 0; parent < archives.size(); ++parent) {
356 if (!done[parent] &&
357 archives[parent].mount_path.IsParent(chain.back().source_path)) {
358 done[parent] = true;
359 chain.push_back(archives[parent]);
360 parent = 0; // Search archives[parent]'s parent from the beginning.
364 // Mount from the tail of chain.
365 for (size_t i = chain.size(); i > 0; --i)
366 DoMountEvent(chromeos::MOUNT_ERROR_NONE, chain[i - 1], kNotRemounting);
370 disk_mount_manager_->RequestMountInfoRefresh();
372 // Subscribe to Profile Preference change.
373 pref_change_registrar_.Init(profile_->GetPrefs());
374 pref_change_registrar_.Add(
375 prefs::kExternalStorageDisabled,
376 base::Bind(&VolumeManager::OnExternalStorageDisabledChanged,
377 weak_ptr_factory_.GetWeakPtr()));
379 // Subscribe to Privet volume lister.
380 if (CommandLine::ForCurrentProcess()->HasSwitch(
381 switches::kEnablePrivetStorage)) {
382 privet_volume_lister_.reset(new local_discovery::PrivetVolumeLister(
383 base::Bind(&VolumeManager::OnPrivetVolumesAvailable,
384 weak_ptr_factory_.GetWeakPtr())));
385 privet_volume_lister_->Start();
388 // Subscribe to storage monitor for MTP notifications.
389 if (CommandLine::ForCurrentProcess()->HasSwitch(
390 chromeos::switches::kEnableFileManagerMTP) &&
391 storage_monitor::StorageMonitor::GetInstance()) {
392 storage_monitor::StorageMonitor::GetInstance()->EnsureInitialized(
393 base::Bind(&VolumeManager::OnStorageMonitorInitialized,
394 weak_ptr_factory_.GetWeakPtr()));
398 void VolumeManager::Shutdown() {
399 weak_ptr_factory_.InvalidateWeakPtrs();
401 pref_change_registrar_.RemoveAll();
402 disk_mount_manager_->RemoveObserver(this);
403 if (storage_monitor::StorageMonitor::GetInstance())
404 storage_monitor::StorageMonitor::GetInstance()->RemoveObserver(this);
406 if (drive_integration_service_)
407 drive_integration_service_->RemoveObserver(this);
409 if (file_system_provider_service_)
410 file_system_provider_service_->RemoveObserver(this);
413 void VolumeManager::AddObserver(VolumeManagerObserver* observer) {
414 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
415 DCHECK(observer);
416 observers_.AddObserver(observer);
419 void VolumeManager::RemoveObserver(VolumeManagerObserver* observer) {
420 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
421 DCHECK(observer);
422 observers_.RemoveObserver(observer);
425 std::vector<VolumeInfo> VolumeManager::GetVolumeInfoList() const {
426 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
428 std::vector<VolumeInfo> result;
429 for (std::map<std::string, VolumeInfo>::const_iterator iter =
430 mounted_volumes_.begin();
431 iter != mounted_volumes_.end();
432 ++iter) {
433 result.push_back(iter->second);
435 return result;
438 bool VolumeManager::FindVolumeInfoById(const std::string& volume_id,
439 VolumeInfo* result) const {
440 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
441 DCHECK(result);
443 std::map<std::string, VolumeInfo>::const_iterator iter =
444 mounted_volumes_.find(volume_id);
445 if (iter == mounted_volumes_.end())
446 return false;
447 *result = iter->second;
448 return true;
451 bool VolumeManager::RegisterDownloadsDirectoryForTesting(
452 const base::FilePath& path) {
453 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
455 base::FilePath old_path;
456 if (FindDownloadsMountPointPath(profile_, &old_path)) {
457 DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
458 CreateDownloadsVolumeInfo(old_path));
461 bool success = RegisterDownloadsMountPoint(profile_, path);
462 DoMountEvent(
463 success ? chromeos::MOUNT_ERROR_NONE : chromeos::MOUNT_ERROR_INVALID_PATH,
464 CreateDownloadsVolumeInfo(path),
465 kNotRemounting);
466 return success;
469 void VolumeManager::AddVolumeInfoForTesting(const base::FilePath& path,
470 VolumeType volume_type,
471 chromeos::DeviceType device_type) {
472 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
473 DoMountEvent(chromeos::MOUNT_ERROR_NONE,
474 CreateTestingVolumeInfo(path, volume_type, device_type),
475 kNotRemounting);
478 void VolumeManager::OnFileSystemMounted() {
479 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
481 // Raise mount event.
482 // We can pass chromeos::MOUNT_ERROR_NONE even when authentication is failed
483 // or network is unreachable. These two errors will be handled later.
484 VolumeInfo volume_info = CreateDriveVolumeInfo(profile_);
485 DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume_info, kNotRemounting);
488 void VolumeManager::OnFileSystemBeingUnmounted() {
489 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
491 VolumeInfo volume_info = CreateDriveVolumeInfo(profile_);
492 DoUnmountEvent(chromeos::MOUNT_ERROR_NONE, volume_info);
495 void VolumeManager::OnDiskEvent(
496 chromeos::disks::DiskMountManager::DiskEvent event,
497 const chromeos::disks::DiskMountManager::Disk* disk) {
498 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
500 // Disregard hidden devices.
501 if (disk->is_hidden())
502 return;
504 switch (event) {
505 case chromeos::disks::DiskMountManager::DISK_ADDED:
506 case chromeos::disks::DiskMountManager::DISK_CHANGED: {
507 if (disk->device_path().empty()) {
508 DVLOG(1) << "Empty system path for " << disk->device_path();
509 return;
512 bool mounting = false;
513 if (disk->mount_path().empty() && disk->has_media() &&
514 !profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
515 // If disk is not mounted yet and it has media and there is no policy
516 // forbidding external storage, give it a try.
517 // Initiate disk mount operation. MountPath auto-detects the filesystem
518 // format if the second argument is empty. The third argument (mount
519 // label) is not used in a disk mount operation.
520 disk_mount_manager_->MountPath(
521 disk->device_path(), std::string(), std::string(),
522 chromeos::MOUNT_TYPE_DEVICE);
523 mounting = true;
526 // Notify to observers.
527 FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
528 OnDiskAdded(*disk, mounting));
529 return;
532 case chromeos::disks::DiskMountManager::DISK_REMOVED:
533 // If the disk is already mounted, unmount it.
534 if (!disk->mount_path().empty()) {
535 disk_mount_manager_->UnmountPath(
536 disk->mount_path(),
537 chromeos::UNMOUNT_OPTIONS_LAZY,
538 chromeos::disks::DiskMountManager::UnmountPathCallback());
541 // Notify to observers.
542 FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
543 OnDiskRemoved(*disk));
544 return;
546 NOTREACHED();
549 void VolumeManager::OnDeviceEvent(
550 chromeos::disks::DiskMountManager::DeviceEvent event,
551 const std::string& device_path) {
552 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
553 DVLOG(1) << "OnDeviceEvent: " << event << ", " << device_path;
555 switch (event) {
556 case chromeos::disks::DiskMountManager::DEVICE_ADDED:
557 FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
558 OnDeviceAdded(device_path));
559 return;
560 case chromeos::disks::DiskMountManager::DEVICE_REMOVED: {
561 const bool hard_unplugged =
562 mounted_disk_monitor_->DeviceIsHardUnplugged(device_path);
563 FOR_EACH_OBSERVER(VolumeManagerObserver,
564 observers_,
565 OnDeviceRemoved(device_path, hard_unplugged));
566 mounted_disk_monitor_->ClearHardUnpluggedFlag(device_path);
567 return;
569 case chromeos::disks::DiskMountManager::DEVICE_SCANNED:
570 DVLOG(1) << "Ignore SCANNED event: " << device_path;
571 return;
573 NOTREACHED();
576 void VolumeManager::OnMountEvent(
577 chromeos::disks::DiskMountManager::MountEvent event,
578 chromeos::MountError error_code,
579 const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) {
580 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
581 DCHECK_NE(chromeos::MOUNT_TYPE_INVALID, mount_info.mount_type);
583 if (mount_info.mount_type == chromeos::MOUNT_TYPE_ARCHIVE) {
584 // If the file is not mounted now, tell it to drive file system so that
585 // it can handle file caching correctly.
586 // Note that drive file system knows if the file is managed by drive file
587 // system or not, so here we report all paths.
588 if ((event == chromeos::disks::DiskMountManager::MOUNTING &&
589 error_code != chromeos::MOUNT_ERROR_NONE) ||
590 (event == chromeos::disks::DiskMountManager::UNMOUNTING &&
591 error_code == chromeos::MOUNT_ERROR_NONE)) {
592 drive::FileSystemInterface* file_system =
593 drive::util::GetFileSystemByProfile(profile_);
594 if (file_system) {
595 file_system->MarkCacheFileAsUnmounted(
596 base::FilePath(mount_info.source_path),
597 base::Bind(&drive::util::EmptyFileOperationCallback));
602 // Notify a mounting/unmounting event to observers.
603 const chromeos::disks::DiskMountManager::Disk* disk =
604 disk_mount_manager_->FindDiskBySourcePath(mount_info.source_path);
605 VolumeInfo volume_info =
606 CreateVolumeInfoFromMountPointInfo(mount_info, disk);
607 switch (event) {
608 case chromeos::disks::DiskMountManager::MOUNTING: {
609 bool is_remounting =
610 disk && mounted_disk_monitor_->DiskIsRemounting(*disk);
611 DoMountEvent(error_code, volume_info, is_remounting);
612 return;
614 case chromeos::disks::DiskMountManager::UNMOUNTING:
615 DoUnmountEvent(error_code, volume_info);
616 return;
618 NOTREACHED();
621 void VolumeManager::OnFormatEvent(
622 chromeos::disks::DiskMountManager::FormatEvent event,
623 chromeos::FormatError error_code,
624 const std::string& device_path) {
625 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
626 DVLOG(1) << "OnDeviceEvent: " << event << ", " << error_code
627 << ", " << device_path;
629 switch (event) {
630 case chromeos::disks::DiskMountManager::FORMAT_STARTED:
631 FOR_EACH_OBSERVER(
632 VolumeManagerObserver, observers_,
633 OnFormatStarted(device_path,
634 error_code == chromeos::FORMAT_ERROR_NONE));
635 return;
636 case chromeos::disks::DiskMountManager::FORMAT_COMPLETED:
637 if (error_code == chromeos::FORMAT_ERROR_NONE) {
638 // If format is completed successfully, try to mount the device.
639 // MountPath auto-detects filesystem format if second argument is
640 // empty. The third argument (mount label) is not used in a disk mount
641 // operation.
642 disk_mount_manager_->MountPath(
643 device_path, std::string(), std::string(),
644 chromeos::MOUNT_TYPE_DEVICE);
647 FOR_EACH_OBSERVER(
648 VolumeManagerObserver, observers_,
649 OnFormatCompleted(device_path,
650 error_code == chromeos::FORMAT_ERROR_NONE));
652 return;
654 NOTREACHED();
657 void VolumeManager::OnProvidedFileSystemMount(
658 const chromeos::file_system_provider::ProvidedFileSystemInfo&
659 file_system_info,
660 base::File::Error error) {
661 VolumeInfo volume_info = CreateProvidedFileSystemVolumeInfo(file_system_info);
662 // TODO(mtomasz): Introduce own type, and avoid using MountError internally,
663 // since it is related to cros disks only.
664 const chromeos::MountError mount_error = error == base::File::FILE_OK
665 ? chromeos::MOUNT_ERROR_NONE
666 : chromeos::MOUNT_ERROR_UNKNOWN;
667 DoMountEvent(mount_error, volume_info, kNotRemounting);
670 void VolumeManager::OnProvidedFileSystemUnmount(
671 const chromeos::file_system_provider::ProvidedFileSystemInfo&
672 file_system_info,
673 base::File::Error error) {
674 // TODO(mtomasz): Introduce own type, and avoid using MountError internally,
675 // since it is related to cros disks only.
676 const chromeos::MountError mount_error = error == base::File::FILE_OK
677 ? chromeos::MOUNT_ERROR_NONE
678 : chromeos::MOUNT_ERROR_UNKNOWN;
679 VolumeInfo volume_info = CreateProvidedFileSystemVolumeInfo(file_system_info);
680 DoUnmountEvent(mount_error, volume_info);
683 void VolumeManager::OnExternalStorageDisabledChanged() {
684 // If the policy just got disabled we have to unmount every device currently
685 // mounted. The opposite is fine - we can let the user re-plug her device to
686 // make it available.
687 if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
688 // We do not iterate on mount_points directly, because mount_points can
689 // be changed by UnmountPath().
690 // TODO(hidehiko): Is it necessary to unmount mounted archives, too, here?
691 while (!disk_mount_manager_->mount_points().empty()) {
692 std::string mount_path =
693 disk_mount_manager_->mount_points().begin()->second.mount_path;
694 disk_mount_manager_->UnmountPath(
695 mount_path,
696 chromeos::UNMOUNT_OPTIONS_NONE,
697 chromeos::disks::DiskMountManager::UnmountPathCallback());
702 void VolumeManager::OnPrivetVolumesAvailable(
703 const local_discovery::PrivetVolumeLister::VolumeList& volumes) {
704 for (local_discovery::PrivetVolumeLister::VolumeList::const_iterator i =
705 volumes.begin(); i != volumes.end(); i++) {
706 VolumeInfo volume_info = CreatePrivetVolumeInfo(*i);
707 DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume_info, false);
711 void VolumeManager::OnRemovableStorageAttached(
712 const storage_monitor::StorageInfo& info) {
713 if (!storage_monitor::StorageInfo::IsMTPDevice(info.device_id()))
714 return;
715 if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled))
716 return;
718 const base::FilePath path = base::FilePath::FromUTF8Unsafe(info.location());
719 const std::string fsid = GetMountPointNameForMediaStorage(info);
720 const std::string name = base::UTF16ToUTF8(info.GetDisplayName(false));
722 bool result =
723 fileapi::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
724 fsid, fileapi::kFileSystemTypeDeviceMediaAsFileStorage,
725 fileapi::FileSystemMountOption(), path);
726 DCHECK(result);
727 content::BrowserThread::PostTask(
728 content::BrowserThread::IO, FROM_HERE, base::Bind(
729 &MTPDeviceMapService::RegisterMTPFileSystem,
730 base::Unretained(MTPDeviceMapService::GetInstance()),
731 info.location(), fsid));
733 VolumeInfo volume_info;
734 volume_info.type = VOLUME_TYPE_MTP;
735 volume_info.mount_path = path;
736 volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
737 volume_info.is_parent = true;
738 volume_info.is_read_only = true;
739 volume_info.volume_id = "mtp:" + name;
740 volume_info.source_path = path;
741 volume_info.device_type = chromeos::DEVICE_TYPE_MOBILE;
742 DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume_info, false);
745 void VolumeManager::OnRemovableStorageDetached(
746 const storage_monitor::StorageInfo& info) {
747 if (!storage_monitor::StorageInfo::IsMTPDevice(info.device_id()))
748 return;
750 for (std::map<std::string, VolumeInfo>::iterator it =
751 mounted_volumes_.begin(); it != mounted_volumes_.end(); ++it) {
752 if (it->second.source_path.value() == info.location()) {
753 DoUnmountEvent(chromeos::MOUNT_ERROR_NONE, VolumeInfo(it->second));
755 const std::string fsid = GetMountPointNameForMediaStorage(info);
756 fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
757 fsid);
758 content::BrowserThread::PostTask(
759 content::BrowserThread::IO, FROM_HERE, base::Bind(
760 &MTPDeviceMapService::RevokeMTPFileSystem,
761 base::Unretained(MTPDeviceMapService::GetInstance()),
762 fsid));
763 return;
768 void VolumeManager::OnStorageMonitorInitialized() {
769 std::vector<storage_monitor::StorageInfo> storages =
770 storage_monitor::StorageMonitor::GetInstance()->GetAllAvailableStorages();
771 for (size_t i = 0; i < storages.size(); ++i)
772 OnRemovableStorageAttached(storages[i]);
773 storage_monitor::StorageMonitor::GetInstance()->AddObserver(this);
776 void VolumeManager::DoMountEvent(chromeos::MountError error_code,
777 const VolumeInfo& volume_info,
778 bool is_remounting) {
779 // Archive files are mounted globally in system. We however don't want to show
780 // archives from profile-specific folders (Drive/Downloads) of other users in
781 // multi-profile session. To this end, we filter out archives not on the
782 // volumes already mounted on this VolumeManager instance.
783 if (volume_info.type == VOLUME_TYPE_MOUNTED_ARCHIVE_FILE) {
784 // Source may be in Drive cache folder under the current profile directory.
785 bool from_current_profile =
786 profile_->GetPath().IsParent(volume_info.source_path);
787 for (std::map<std::string, VolumeInfo>::const_iterator iter =
788 mounted_volumes_.begin();
789 !from_current_profile && iter != mounted_volumes_.end();
790 ++iter) {
791 if (iter->second.mount_path.IsParent(volume_info.source_path))
792 from_current_profile = true;
794 if (!from_current_profile)
795 return;
798 // Filter out removable disks if forbidden by policy for this profile.
799 if (volume_info.type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION &&
800 profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
801 return;
804 if (error_code == chromeos::MOUNT_ERROR_NONE || volume_info.mount_condition)
805 mounted_volumes_[volume_info.volume_id] = volume_info;
807 FOR_EACH_OBSERVER(VolumeManagerObserver,
808 observers_,
809 OnVolumeMounted(error_code, volume_info, is_remounting));
812 void VolumeManager::DoUnmountEvent(chromeos::MountError error_code,
813 const VolumeInfo& volume_info) {
814 if (mounted_volumes_.find(volume_info.volume_id) == mounted_volumes_.end())
815 return;
816 if (error_code == chromeos::MOUNT_ERROR_NONE)
817 mounted_volumes_.erase(volume_info.volume_id);
819 FOR_EACH_OBSERVER(VolumeManagerObserver,
820 observers_,
821 OnVolumeUnmounted(error_code, volume_info));
824 } // namespace file_manager