Chromium Code Reviews| 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 EnsureMountInfoRefrehsed(). 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 RefreshEachDevice(devices, 0); | |
| 483 } | |
| 484 | |
| 485 // Part of EnsureMountInfoRefrehsed(). Called for each device to refresh info. | |
| 486 void RefreshEachDevice(const std::vector<std::string>& devices, size_t i) { | |
|
Ben Chan
2014/07/10 00:07:12
i -> index
RefreshEachDevice seems like a misnome
kinaba
2014/07/10 01:36:32
Done.
| |
| 487 if (i == devices.size()) { | |
| 488 // All devices info retrieved. Proceed to enumerate mount point info. | |
| 489 cros_disks_client_->EnumerateMountEntries( | |
| 490 base::Bind(&DiskMountManagerImpl::RefreshAfterEnumerateMountEntries, | |
| 491 weak_ptr_factory_.GetWeakPtr()), | |
| 492 base::Bind(&DiskMountManagerImpl::RefreshCompleted, | |
| 493 weak_ptr_factory_.GetWeakPtr(), false)); | |
| 494 return; | |
| 495 } | |
| 496 | |
| 497 cros_disks_client_->GetDeviceProperties( | |
| 498 devices[i], | |
| 499 base::Bind(&DiskMountManagerImpl::RefreshAfterGetDeviceProperties, | |
| 500 weak_ptr_factory_.GetWeakPtr(), devices, i + 1), | |
| 501 base::Bind(&DiskMountManagerImpl::RefreshCompleted, | |
| 502 weak_ptr_factory_.GetWeakPtr(), false)); | |
| 503 } | |
| 504 | |
| 505 // Part of EnsureMountInfoRefrehsed(). | |
|
Ben Chan
2014/07/10 00:07:12
typo: EnsureMountInfoRefrehsed -> EnsureMountInfoR
kinaba
2014/07/10 01:36:32
Done. Good eye :)
| |
| 506 void RefreshAfterGetDeviceProperties(const std::vector<std::string>& devices, | |
| 507 size_t next_index, | |
| 508 const DiskInfo& disk_info) { | |
| 509 OnGetDeviceProperties(disk_info); | |
| 510 RefreshEachDevice(devices, next_index); | |
| 511 } | |
| 512 | |
| 513 // Part of EnsureMountInfoRefrehsed(). Called after mount entries are listed. | |
| 514 void RefreshAfterEnumerateMountEntries( | |
| 515 const std::vector<MountEntry>& entries) { | |
| 516 for (size_t i = 0; i < entries.size(); ++i) | |
| 517 OnMountCompleted(entries[i]); | |
| 518 RefreshCompleted(true); | |
| 519 } | |
| 520 | |
| 521 // Part of EnsureMountInfoRefrehsed(). Called when the refreshing is done. | |
| 522 void RefreshCompleted(bool success) { | |
| 523 already_refreshed_ = true; | |
| 524 for (size_t i = 0; i < refresh_callbacks_.size(); ++i) | |
| 525 refresh_callbacks_[i].Run(success); | |
| 526 refresh_callbacks_.clear(); | |
| 483 } | 527 } |
| 484 | 528 |
| 485 // Callback to handle mount event signals. | 529 // Callback to handle mount event signals. |
| 486 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { | 530 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { |
| 487 // Take a copy of the argument so we can modify it below. | 531 // Take a copy of the argument so we can modify it below. |
| 488 std::string device_path = device_path_arg; | 532 std::string device_path = device_path_arg; |
| 489 switch (event) { | 533 switch (event) { |
| 490 case CROS_DISKS_DISK_ADDED: { | 534 case CROS_DISKS_DISK_ADDED: { |
| 491 cros_disks_client_->GetDeviceProperties( | 535 cros_disks_client_->GetDeviceProperties( |
| 492 device_path, | 536 device_path, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 CrosDisksClient* cros_disks_client_; | 617 CrosDisksClient* cros_disks_client_; |
| 574 | 618 |
| 575 // The list of disks found. | 619 // The list of disks found. |
| 576 DiskMountManager::DiskMap disks_; | 620 DiskMountManager::DiskMap disks_; |
| 577 | 621 |
| 578 DiskMountManager::MountPointMap mount_points_; | 622 DiskMountManager::MountPointMap mount_points_; |
| 579 | 623 |
| 580 typedef std::set<std::string> SystemPathPrefixSet; | 624 typedef std::set<std::string> SystemPathPrefixSet; |
| 581 SystemPathPrefixSet system_path_prefixes_; | 625 SystemPathPrefixSet system_path_prefixes_; |
| 582 | 626 |
| 627 bool already_refreshed_; | |
| 628 std::vector<EnsureMountInfoRefreshedCallback> refresh_callbacks_; | |
| 629 | |
| 583 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; | 630 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; |
| 584 | 631 |
| 585 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); | 632 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); |
| 586 }; | 633 }; |
| 587 | 634 |
| 588 } // namespace | 635 } // namespace |
| 589 | 636 |
| 590 DiskMountManager::Disk::Disk(const std::string& device_path, | 637 DiskMountManager::Disk::Disk(const std::string& device_path, |
| 591 const std::string& mount_path, | 638 const std::string& mount_path, |
| 592 const std::string& system_path, | 639 const std::string& system_path, |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 VLOG(1) << "DiskMountManager Shutdown completed"; | 747 VLOG(1) << "DiskMountManager Shutdown completed"; |
| 701 } | 748 } |
| 702 | 749 |
| 703 // static | 750 // static |
| 704 DiskMountManager* DiskMountManager::GetInstance() { | 751 DiskMountManager* DiskMountManager::GetInstance() { |
| 705 return g_disk_mount_manager; | 752 return g_disk_mount_manager; |
| 706 } | 753 } |
| 707 | 754 |
| 708 } // namespace disks | 755 } // namespace disks |
| 709 } // namespace chromeos | 756 } // namespace chromeos |
| OLD | NEW |