OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chromeos/disks/disk_mount_manager.h" | 5 #include "chromeos/disks/disk_mount_manager.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/memory/weak_ptr.h" | 11 #include "base/memory/weak_ptr.h" |
12 #include "base/observer_list.h" | 12 #include "base/observer_list.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "chromeos/dbus/dbus_thread_manager.h" | 15 #include "chromeos/dbus/dbus_thread_manager.h" |
16 | 16 |
17 namespace chromeos { | 17 namespace chromeos { |
18 namespace disks { | 18 namespace disks { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 const char kDeviceNotFound[] = "Device could not be found"; | 22 const char kDeviceNotFound[] = "Device could not be found"; |
23 | 23 |
24 DiskMountManager* g_disk_mount_manager = NULL; | 24 DiskMountManager* g_disk_mount_manager = NULL; |
25 | 25 |
26 // The DiskMountManager implementation. | 26 // The DiskMountManager implementation. |
27 class DiskMountManagerImpl : public DiskMountManager { | 27 class DiskMountManagerImpl : public DiskMountManager { |
28 public: | 28 public: |
29 DiskMountManagerImpl() : weak_ptr_factory_(this) { | 29 DiskMountManagerImpl() : |
| 30 already_refreshed_(false), |
| 31 weak_ptr_factory_(this) { |
30 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); | 32 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); |
31 DCHECK(dbus_thread_manager); | 33 DCHECK(dbus_thread_manager); |
32 cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient(); | 34 cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient(); |
33 DCHECK(cros_disks_client_); | 35 DCHECK(cros_disks_client_); |
34 cros_disks_client_->SetMountEventHandler( | 36 cros_disks_client_->SetMountEventHandler( |
35 base::Bind(&DiskMountManagerImpl::OnMountEvent, | 37 base::Bind(&DiskMountManagerImpl::OnMountEvent, |
36 weak_ptr_factory_.GetWeakPtr())); | 38 weak_ptr_factory_.GetWeakPtr())); |
37 cros_disks_client_->SetMountCompletedHandler( | 39 cros_disks_client_->SetMountCompletedHandler( |
38 base::Bind(&DiskMountManagerImpl::OnMountCompleted, | 40 base::Bind(&DiskMountManagerImpl::OnMountCompleted, |
39 weak_ptr_factory_.GetWeakPtr())); | 41 weak_ptr_factory_.GetWeakPtr())); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 callback.Run(false); | 150 callback.Run(false); |
149 return; | 151 return; |
150 } | 152 } |
151 | 153 |
152 // Nothing to unmount. | 154 // Nothing to unmount. |
153 callback.Run(true); | 155 callback.Run(true); |
154 return; | 156 return; |
155 } | 157 } |
156 | 158 |
157 // We will send the same callback data object to all Unmount calls and use | 159 // We will send the same callback data object to all Unmount calls and use |
158 // it to syncronize callbacks. | 160 // it to synchronize callbacks. |
159 // Note: this implementation has a potential memory leak issue. For | 161 // Note: this implementation has a potential memory leak issue. For |
160 // example if this instance is destructed before all the callbacks for | 162 // example if this instance is destructed before all the callbacks for |
161 // Unmount are invoked, the memory pointed by |cb_data| will be leaked. | 163 // Unmount are invoked, the memory pointed by |cb_data| will be leaked. |
162 // It is because the UnmountDeviceRecursivelyCallbackData keeps how | 164 // It is because the UnmountDeviceRecursivelyCallbackData keeps how |
163 // many times OnUnmountDeviceRecursively callback is called and when | 165 // many times OnUnmountDeviceRecursively callback is called and when |
164 // all the callbacks are called, |cb_data| will be deleted in the method. | 166 // all the callbacks are called, |cb_data| will be deleted in the method. |
165 // However destructing the instance before all callback invocations will | 167 // However destructing the instance before all callback invocations will |
166 // cancel all pending callbacks, so that the |cb_data| would never be | 168 // cancel all pending callbacks, so that the |cb_data| would never be |
167 // deleted. | 169 // deleted. |
168 // Fortunately, in the real scenario, the instance will be destructed | 170 // Fortunately, in the real scenario, the instance will be destructed |
(...skipping 13 matching lines...) Expand all Loading... |
182 devices_to_unmount[i]), | 184 devices_to_unmount[i]), |
183 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively, | 185 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively, |
184 weak_ptr_factory_.GetWeakPtr(), | 186 weak_ptr_factory_.GetWeakPtr(), |
185 cb_data, | 187 cb_data, |
186 false, | 188 false, |
187 devices_to_unmount[i])); | 189 devices_to_unmount[i])); |
188 } | 190 } |
189 } | 191 } |
190 | 192 |
191 // DiskMountManager override. | 193 // DiskMountManager override. |
192 virtual void RequestMountInfoRefresh() OVERRIDE { | 194 virtual void EnsureMountInfoRefreshed( |
193 cros_disks_client_->EnumerateAutoMountableDevices( | 195 const EnsureMountInfoRefreshedCallback& callback) OVERRIDE { |
194 base::Bind(&DiskMountManagerImpl::OnRequestMountInfo, | 196 if (already_refreshed_) { |
195 weak_ptr_factory_.GetWeakPtr()), | 197 callback.Run(true); |
196 base::Bind(&base::DoNothing)); | 198 return; |
| 199 } |
| 200 |
| 201 refresh_callbacks_.push_back(callback); |
| 202 if (refresh_callbacks_.size() == 1) { |
| 203 // If there's no in-flight refreshing task, start it. |
| 204 cros_disks_client_->EnumerateAutoMountableDevices( |
| 205 base::Bind(&DiskMountManagerImpl::RefreshAfterEnumerateDevices, |
| 206 weak_ptr_factory_.GetWeakPtr()), |
| 207 base::Bind(&DiskMountManagerImpl::RefreshCompleted, |
| 208 weak_ptr_factory_.GetWeakPtr(), false)); |
| 209 } |
197 } | 210 } |
198 | 211 |
199 // DiskMountManager override. | 212 // DiskMountManager override. |
200 virtual const DiskMap& disks() const OVERRIDE { return disks_; } | 213 virtual const DiskMap& disks() const OVERRIDE { return disks_; } |
201 | 214 |
202 // DiskMountManager override. | 215 // DiskMountManager override. |
203 virtual const Disk* FindDiskBySourcePath(const std::string& source_path) | 216 virtual const Disk* FindDiskBySourcePath(const std::string& source_path) |
204 const OVERRIDE { | 217 const OVERRIDE { |
205 DiskMap::const_iterator disk_it = disks_.find(source_path); | 218 DiskMap::const_iterator disk_it = disks_.find(source_path); |
206 return disk_it == disks_.end() ? NULL : disk_it->second; | 219 return disk_it == disks_.end() ? NULL : disk_it->second; |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 void OnFormatStarted(const std::string& device_path) { | 420 void OnFormatStarted(const std::string& device_path) { |
408 NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path); | 421 NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path); |
409 } | 422 } |
410 | 423 |
411 // Callback to handle FormatCompleted signal and Format method call failure. | 424 // Callback to handle FormatCompleted signal and Format method call failure. |
412 void OnFormatCompleted(FormatError error_code, | 425 void OnFormatCompleted(FormatError error_code, |
413 const std::string& device_path) { | 426 const std::string& device_path) { |
414 NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path); | 427 NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path); |
415 } | 428 } |
416 | 429 |
417 // Callbcak for GetDeviceProperties. | 430 // Callback for GetDeviceProperties. |
418 void OnGetDeviceProperties(const DiskInfo& disk_info) { | 431 void OnGetDeviceProperties(const DiskInfo& disk_info) { |
419 // TODO(zelidrag): Find a better way to filter these out before we | 432 // TODO(zelidrag): Find a better way to filter these out before we |
420 // fetch the properties: | 433 // fetch the properties: |
421 // Ignore disks coming from the device we booted the system from. | 434 // Ignore disks coming from the device we booted the system from. |
422 if (disk_info.on_boot_device()) | 435 if (disk_info.on_boot_device()) |
423 return; | 436 return; |
424 | 437 |
425 LOG(WARNING) << "Found disk " << disk_info.device_path(); | 438 LOG(WARNING) << "Found disk " << disk_info.device_path(); |
426 // Delete previous disk info for this path: | 439 // Delete previous disk info for this path: |
427 bool is_new = true; | 440 bool is_new = true; |
(...skipping 19 matching lines...) Expand all Loading... |
447 disk_info.total_size_in_bytes(), | 460 disk_info.total_size_in_bytes(), |
448 disk_info.is_drive(), | 461 disk_info.is_drive(), |
449 disk_info.is_read_only(), | 462 disk_info.is_read_only(), |
450 disk_info.has_media(), | 463 disk_info.has_media(), |
451 disk_info.on_boot_device(), | 464 disk_info.on_boot_device(), |
452 disk_info.is_hidden()); | 465 disk_info.is_hidden()); |
453 disks_.insert(std::make_pair(disk_info.device_path(), disk)); | 466 disks_.insert(std::make_pair(disk_info.device_path(), disk)); |
454 NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, disk); | 467 NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, disk); |
455 } | 468 } |
456 | 469 |
457 // Callbcak for RequestMountInfo. | 470 // Part of EnsureMountInfoRefreshed(). Called after the list of devices are |
458 void OnRequestMountInfo(const std::vector<std::string>& devices) { | 471 // enumerated. |
459 std::set<std::string> current_device_set; | 472 void RefreshAfterEnumerateDevices(const std::vector<std::string>& devices) { |
460 if (!devices.empty()) { | 473 std::set<std::string> current_device_set(devices.begin(), devices.end()); |
461 // Initiate properties fetch for all removable disks, | |
462 for (size_t i = 0; i < devices.size(); i++) { | |
463 current_device_set.insert(devices[i]); | |
464 // Initiate disk property retrieval for each relevant device path. | |
465 cros_disks_client_->GetDeviceProperties( | |
466 devices[i], | |
467 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, | |
468 weak_ptr_factory_.GetWeakPtr()), | |
469 base::Bind(&base::DoNothing)); | |
470 } | |
471 } | |
472 // Search and remove disks that are no longer present. | |
473 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) { | 474 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) { |
474 if (current_device_set.find(iter->first) == current_device_set.end()) { | 475 if (current_device_set.find(iter->first) == current_device_set.end()) { |
475 Disk* disk = iter->second; | |
476 NotifyDiskStatusUpdate(DISK_REMOVED, disk); | |
477 delete iter->second; | 476 delete iter->second; |
478 disks_.erase(iter++); | 477 disks_.erase(iter++); |
479 } else { | 478 } else { |
480 ++iter; | 479 ++iter; |
481 } | 480 } |
482 } | 481 } |
| 482 RefreshDeviceAtIndex(devices, 0); |
| 483 } |
| 484 |
| 485 // Part of EnsureMountInfoRefreshed(). Called for each device to refresh info. |
| 486 void RefreshDeviceAtIndex(const std::vector<std::string>& devices, |
| 487 size_t index) { |
| 488 if (index == devices.size()) { |
| 489 // All devices info retrieved. Proceed to enumerate mount point info. |
| 490 cros_disks_client_->EnumerateMountEntries( |
| 491 base::Bind(&DiskMountManagerImpl::RefreshAfterEnumerateMountEntries, |
| 492 weak_ptr_factory_.GetWeakPtr()), |
| 493 base::Bind(&DiskMountManagerImpl::RefreshCompleted, |
| 494 weak_ptr_factory_.GetWeakPtr(), false)); |
| 495 return; |
| 496 } |
| 497 |
| 498 cros_disks_client_->GetDeviceProperties( |
| 499 devices[index], |
| 500 base::Bind(&DiskMountManagerImpl::RefreshAfterGetDeviceProperties, |
| 501 weak_ptr_factory_.GetWeakPtr(), devices, index + 1), |
| 502 base::Bind(&DiskMountManagerImpl::RefreshCompleted, |
| 503 weak_ptr_factory_.GetWeakPtr(), false)); |
| 504 } |
| 505 |
| 506 // Part of EnsureMountInfoRefreshed(). |
| 507 void RefreshAfterGetDeviceProperties(const std::vector<std::string>& devices, |
| 508 size_t next_index, |
| 509 const DiskInfo& disk_info) { |
| 510 OnGetDeviceProperties(disk_info); |
| 511 RefreshDeviceAtIndex(devices, next_index); |
| 512 } |
| 513 |
| 514 // Part of EnsureMountInfoRefreshed(). Called after mount entries are listed. |
| 515 void RefreshAfterEnumerateMountEntries( |
| 516 const std::vector<MountEntry>& entries) { |
| 517 for (size_t i = 0; i < entries.size(); ++i) |
| 518 OnMountCompleted(entries[i]); |
| 519 RefreshCompleted(true); |
| 520 } |
| 521 |
| 522 // Part of EnsureMountInfoRefreshed(). Called when the refreshing is done. |
| 523 void RefreshCompleted(bool success) { |
| 524 already_refreshed_ = true; |
| 525 for (size_t i = 0; i < refresh_callbacks_.size(); ++i) |
| 526 refresh_callbacks_[i].Run(success); |
| 527 refresh_callbacks_.clear(); |
483 } | 528 } |
484 | 529 |
485 // Callback to handle mount event signals. | 530 // Callback to handle mount event signals. |
486 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { | 531 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { |
487 // Take a copy of the argument so we can modify it below. | 532 // Take a copy of the argument so we can modify it below. |
488 std::string device_path = device_path_arg; | 533 std::string device_path = device_path_arg; |
489 switch (event) { | 534 switch (event) { |
490 case CROS_DISKS_DISK_ADDED: { | 535 case CROS_DISKS_DISK_ADDED: { |
491 cros_disks_client_->GetDeviceProperties( | 536 cros_disks_client_->GetDeviceProperties( |
492 device_path, | 537 device_path, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 CrosDisksClient* cros_disks_client_; | 618 CrosDisksClient* cros_disks_client_; |
574 | 619 |
575 // The list of disks found. | 620 // The list of disks found. |
576 DiskMountManager::DiskMap disks_; | 621 DiskMountManager::DiskMap disks_; |
577 | 622 |
578 DiskMountManager::MountPointMap mount_points_; | 623 DiskMountManager::MountPointMap mount_points_; |
579 | 624 |
580 typedef std::set<std::string> SystemPathPrefixSet; | 625 typedef std::set<std::string> SystemPathPrefixSet; |
581 SystemPathPrefixSet system_path_prefixes_; | 626 SystemPathPrefixSet system_path_prefixes_; |
582 | 627 |
| 628 bool already_refreshed_; |
| 629 std::vector<EnsureMountInfoRefreshedCallback> refresh_callbacks_; |
| 630 |
583 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; | 631 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; |
584 | 632 |
585 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); | 633 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); |
586 }; | 634 }; |
587 | 635 |
588 } // namespace | 636 } // namespace |
589 | 637 |
590 DiskMountManager::Disk::Disk(const std::string& device_path, | 638 DiskMountManager::Disk::Disk(const std::string& device_path, |
591 const std::string& mount_path, | 639 const std::string& mount_path, |
592 const std::string& system_path, | 640 const std::string& system_path, |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 VLOG(1) << "DiskMountManager Shutdown completed"; | 748 VLOG(1) << "DiskMountManager Shutdown completed"; |
701 } | 749 } |
702 | 750 |
703 // static | 751 // static |
704 DiskMountManager* DiskMountManager::GetInstance() { | 752 DiskMountManager* DiskMountManager::GetInstance() { |
705 return g_disk_mount_manager; | 753 return g_disk_mount_manager; |
706 } | 754 } |
707 | 755 |
708 } // namespace disks | 756 } // namespace disks |
709 } // namespace chromeos | 757 } // namespace chromeos |
OLD | NEW |