suspend_unmount_manager.cc 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright 2015 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.
  4. #include "ash/components/disks/suspend_unmount_manager.h"
  5. #include "ash/components/disks/disk.h"
  6. #include "ash/components/disks/disk_mount_manager.h"
  7. #include "base/bind.h"
  8. #include "base/location.h"
  9. #include "base/logging.h"
  10. namespace ash {
  11. namespace disks {
  12. namespace {
  13. // Threshold for logging the blocking of suspend.
  14. constexpr base::TimeDelta kBlockSuspendThreshold = base::Seconds(5);
  15. void OnRefreshCompleted(bool success) {}
  16. } // namespace
  17. SuspendUnmountManager::SuspendUnmountManager(
  18. DiskMountManager* disk_mount_manager)
  19. : disk_mount_manager_(disk_mount_manager) {
  20. PowerManagerClient::Get()->AddObserver(this);
  21. }
  22. SuspendUnmountManager::~SuspendUnmountManager() {
  23. PowerManagerClient::Get()->RemoveObserver(this);
  24. if (block_suspend_token_)
  25. PowerManagerClient::Get()->UnblockSuspend(block_suspend_token_);
  26. }
  27. void SuspendUnmountManager::SuspendImminent(
  28. power_manager::SuspendImminent::Reason reason) {
  29. DCHECK(unmounting_paths_.empty());
  30. if (!unmounting_paths_.empty())
  31. return;
  32. std::set<std::string> mount_paths;
  33. for (const auto& disk : disk_mount_manager_->disks()) {
  34. if ((disk->device_type() == DeviceType::kUSB ||
  35. disk->device_type() == DeviceType::kSD) &&
  36. !disk->mount_path().empty()) {
  37. mount_paths.insert(disk->mount_path());
  38. }
  39. }
  40. for (const auto& mount_path : mount_paths) {
  41. if (block_suspend_token_.is_empty()) {
  42. block_suspend_token_ = base::UnguessableToken::Create();
  43. block_suspend_time_ = base::TimeTicks::Now();
  44. PowerManagerClient::Get()->BlockSuspend(block_suspend_token_,
  45. "SuspendUnmountManager");
  46. }
  47. disk_mount_manager_->UnmountPath(
  48. mount_path, base::BindOnce(&SuspendUnmountManager::OnUnmountComplete,
  49. weak_ptr_factory_.GetWeakPtr(), mount_path));
  50. unmounting_paths_.insert(mount_path);
  51. }
  52. }
  53. void SuspendUnmountManager::SuspendDone(base::TimeDelta sleep_duration) {
  54. // SuspendDone can be called before OnUnmountComplete when suspend is
  55. // cancelled, or it takes long time to unmount volumes.
  56. unmounting_paths_.clear();
  57. disk_mount_manager_->EnsureMountInfoRefreshed(
  58. base::BindOnce(&OnRefreshCompleted), true /* force */);
  59. block_suspend_token_ = {};
  60. }
  61. void SuspendUnmountManager::OnUnmountComplete(const std::string& mount_path,
  62. MountError error_code) {
  63. // This can happen when unmount completes after suspend done is called.
  64. if (unmounting_paths_.erase(mount_path) != 1)
  65. return;
  66. if (unmounting_paths_.empty() && block_suspend_token_) {
  67. PowerManagerClient::Get()->UnblockSuspend(block_suspend_token_);
  68. block_suspend_token_ = {};
  69. auto block_time = base::TimeTicks::Now() - block_suspend_time_;
  70. LOG_IF(WARNING, block_time > kBlockSuspendThreshold)
  71. << "Blocked suspend for " << block_time.InSecondsF() << " seconds";
  72. }
  73. }
  74. } // namespace disks
  75. } // namespace ash