summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhirono <hirono@chromium.org>2015-06-21 21:28:41 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-22 04:29:21 +0000
commit9f5eae54a21c440056afffc0b52fa3d07ae3f5eb (patch)
treebf5d33338ad4d4f343a25bd3944239755e41b5f9
parent730e0fed9bd25d464fc85d67a34e778ae58c720e (diff)
downloadchromium_src-9f5eae54a21c440056afffc0b52fa3d07ae3f5eb.zip
chromium_src-9f5eae54a21c440056afffc0b52fa3d07ae3f5eb.tar.gz
chromium_src-9f5eae54a21c440056afffc0b52fa3d07ae3f5eb.tar.bz2
Unmount USB devices when the machine is being suspended.
This CL adds SuspendUnmountManager to DiskMountManager to unmount all USB volumes before the machine is suspended. The class records the paths of unmounted volumes, and remount them in the future CL. BUG=434372 TEST=SuspendUnmountManagerTest Review URL: https://codereview.chromium.org/862433003 Cr-Commit-Position: refs/heads/master@{#335472}
-rw-r--r--chromeos/chromeos.gyp3
-rw-r--r--chromeos/disks/disk_mount_manager.cc9
-rw-r--r--chromeos/disks/suspend_unmount_manager.cc71
-rw-r--r--chromeos/disks/suspend_unmount_manager.h54
-rw-r--r--chromeos/disks/suspend_unmount_manager_unittest.cc91
5 files changed, 226 insertions, 2 deletions
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index b98e2605..d11f212 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -288,6 +288,8 @@
'dbus/volume_state.h',
'disks/disk_mount_manager.cc',
'disks/disk_mount_manager.h',
+ 'disks/suspend_unmount_manager.cc',
+ 'disks/suspend_unmount_manager.h',
'geolocation/geoposition.cc',
'geolocation/geoposition.h',
'geolocation/simple_geolocation_provider.cc',
@@ -491,6 +493,7 @@
'dbus/shill_service_client_unittest.cc',
'dbus/shill_third_party_vpn_driver_client_unittest.cc',
'disks/disk_mount_manager_unittest.cc',
+ 'disks/suspend_unmount_manager_unittest.cc',
'geolocation/simple_geolocation_unittest.cc',
'login/auth/key_unittest.cc',
'login/login_state_unittest.cc',
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc
index 36e4c46..a046b21 100644
--- a/chromeos/disks/disk_mount_manager.cc
+++ b/chromeos/disks/disk_mount_manager.cc
@@ -12,6 +12,7 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/disks/suspend_unmount_manager.h"
namespace chromeos {
namespace disks {
@@ -29,9 +30,11 @@ class DiskMountManagerImpl : public DiskMountManager {
already_refreshed_(false),
weak_ptr_factory_(this) {
DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get();
- DCHECK(dbus_thread_manager);
cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient();
- DCHECK(cros_disks_client_);
+ PowerManagerClient* power_manager_client =
+ dbus_thread_manager->GetPowerManagerClient();
+ suspend_unmount_manager_.reset(
+ new SuspendUnmountManager(this, power_manager_client));
cros_disks_client_->SetMountEventHandler(
base::Bind(&DiskMountManagerImpl::OnMountEvent,
weak_ptr_factory_.GetWeakPtr()));
@@ -625,6 +628,8 @@ class DiskMountManagerImpl : public DiskMountManager {
bool already_refreshed_;
std::vector<EnsureMountInfoRefreshedCallback> refresh_callbacks_;
+ scoped_ptr<SuspendUnmountManager> suspend_unmount_manager_;
+
base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl);
diff --git a/chromeos/disks/suspend_unmount_manager.cc b/chromeos/disks/suspend_unmount_manager.cc
new file mode 100644
index 0000000..dfed1ed
--- /dev/null
+++ b/chromeos/disks/suspend_unmount_manager.cc
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/disks/suspend_unmount_manager.h"
+
+#include "base/bind.h"
+#include "chromeos/disks/disk_mount_manager.h"
+
+namespace chromeos {
+namespace disks {
+
+SuspendUnmountManager::SuspendUnmountManager(
+ DiskMountManager* disk_mount_manager,
+ PowerManagerClient* power_manager_client)
+ : disk_mount_manager_(disk_mount_manager),
+ power_manager_client_(power_manager_client),
+ weak_ptr_factory_(this) {
+ power_manager_client_->AddObserver(this);
+}
+
+SuspendUnmountManager::~SuspendUnmountManager() {
+ power_manager_client_->RemoveObserver(this);
+ if (!suspend_readiness_callback_.is_null())
+ suspend_readiness_callback_.Run();
+}
+
+void SuspendUnmountManager::SuspendImminent() {
+ DCHECK(unmounting_paths_.empty());
+ if (!unmounting_paths_.empty())
+ return;
+ std::set<std::string> mount_paths;
+ for (const auto& pair : disk_mount_manager_->disks()) {
+ if (pair.second->device_type() == DEVICE_TYPE_USB &&
+ !pair.second->mount_path().empty()) {
+ mount_paths.insert(pair.second->mount_path());
+ }
+ }
+ for (const auto& mount_path : mount_paths) {
+ if (suspend_readiness_callback_.is_null()) {
+ suspend_readiness_callback_ =
+ power_manager_client_->GetSuspendReadinessCallback();
+ }
+ disk_mount_manager_->UnmountPath(
+ mount_path, UNMOUNT_OPTIONS_NONE,
+ base::Bind(&SuspendUnmountManager::OnUnmountComplete,
+ weak_ptr_factory_.GetWeakPtr(), mount_path));
+ unmounting_paths_.insert(mount_path);
+ }
+}
+
+void SuspendUnmountManager::SuspendDone(const base::TimeDelta& sleep_duration) {
+ // SuspendDone can be called before OnUnmountComplete when suspend is
+ // cancelled, or it takes long time to unmount volumes.
+ unmounting_paths_.clear();
+ suspend_readiness_callback_.Reset();
+}
+
+void SuspendUnmountManager::OnUnmountComplete(const std::string& mount_path,
+ chromeos::MountError error_code) {
+ // This can happen when unmount completes after suspend done is called.
+ if (unmounting_paths_.erase(mount_path) != 1)
+ return;
+ if (unmounting_paths_.empty() && !suspend_readiness_callback_.is_null()) {
+ suspend_readiness_callback_.Run();
+ suspend_readiness_callback_.Reset();
+ }
+}
+
+} // namespace chromeos
+} // namespace disks
diff --git a/chromeos/disks/suspend_unmount_manager.h b/chromeos/disks/suspend_unmount_manager.h
new file mode 100644
index 0000000..b52687c
--- /dev/null
+++ b/chromeos/disks/suspend_unmount_manager.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DISKS_SUSPEND_UNMOUNT_MANAGER_H_
+#define CHROMEOS_DISKS_SUSPEND_UNMOUNT_MANAGER_H_
+
+#include <set>
+#include <string>
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/cros_disks_client.h"
+#include "chromeos/dbus/power_manager_client.h"
+
+namespace chromeos {
+namespace disks {
+
+class DiskMountManager;
+
+// Class to unmount disks at suspend.
+class CHROMEOS_EXPORT SuspendUnmountManager
+ : public PowerManagerClient::Observer {
+ public:
+ // The ownership of these raw pointers still remains with the caller.
+ SuspendUnmountManager(DiskMountManager* disk_mount_manager,
+ PowerManagerClient* power_manager_client);
+ ~SuspendUnmountManager() override;
+
+ private:
+ void OnUnmountComplete(const std::string& mount_path,
+ chromeos::MountError error_code);
+
+ // PowerManagerClient::Observer
+ void SuspendImminent() override;
+ void SuspendDone(const base::TimeDelta& sleep_duration) override;
+
+ // Callback passed to DiskMountManager holds weak pointers of this.
+ DiskMountManager* const disk_mount_manager_;
+ PowerManagerClient* const power_manager_client_;
+
+ // The paths that the manager currently tries to unmount for suspend.
+ std::set<std::string> unmounting_paths_;
+
+ base::Closure suspend_readiness_callback_;
+
+ base::WeakPtrFactory<SuspendUnmountManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SuspendUnmountManager);
+};
+
+} // namespace disks
+} // namespace chromeos
+
+#endif // CHROMEOS_DISKS_SUSPEND_UNMOUNT_MANAGER_H_
diff --git a/chromeos/disks/suspend_unmount_manager_unittest.cc b/chromeos/disks/suspend_unmount_manager_unittest.cc
new file mode 100644
index 0000000..d6a8ef8
--- /dev/null
+++ b/chromeos/disks/suspend_unmount_manager_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/fake_power_manager_client.h"
+#include "chromeos/disks/disk_mount_manager.h"
+#include "chromeos/disks/mock_disk_mount_manager.h"
+#include "chromeos/disks/suspend_unmount_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace disks {
+namespace {
+
+class FakeDiskMountManager : public MockDiskMountManager {
+ public:
+ void NotifyUnmountDeviceComplete(MountError error) const {
+ callback_.Run(error);
+ }
+
+ const std::vector<std::string>& unmounting_mount_paths() const {
+ return unmounting_mount_paths_;
+ }
+
+ private:
+ void UnmountPath(const std::string& mount_path,
+ UnmountOptions options,
+ const UnmountPathCallback& callback) override {
+ unmounting_mount_paths_.push_back(mount_path);
+ callback_ = callback;
+ }
+ std::vector<std::string> unmounting_mount_paths_;
+ UnmountPathCallback callback_;
+};
+
+class SuspendUnmountManagerTest : public testing::Test {
+ public:
+ SuspendUnmountManagerTest()
+ : suspend_unmount_manager_(&disk_mount_manager_, &fake_power_client_) {}
+ ~SuspendUnmountManagerTest() override {}
+
+ protected:
+ FakeDiskMountManager disk_mount_manager_;
+ FakePowerManagerClient fake_power_client_;
+ SuspendUnmountManager suspend_unmount_manager_;
+};
+
+TEST_F(SuspendUnmountManagerTest, Basic) {
+ const std::string dummy_mount_path = "/dummy/mount";
+ disk_mount_manager_.CreateDiskEntryForMountDevice(
+ chromeos::disks::DiskMountManager::MountPointInfo(
+ "/dummy/device", dummy_mount_path, chromeos::MOUNT_TYPE_DEVICE,
+ chromeos::disks::MOUNT_CONDITION_NONE),
+ "device_id", "device_label", "Vendor", "Product",
+ chromeos::DEVICE_TYPE_USB, 1024 * 1024, true, true, true, false);
+ disk_mount_manager_.SetupDefaultReplies();
+ fake_power_client_.SendSuspendImminent();
+
+ EXPECT_EQ(1, fake_power_client_.GetNumPendingSuspendReadinessCallbacks());
+ ASSERT_EQ(1u, disk_mount_manager_.unmounting_mount_paths().size());
+ EXPECT_EQ(dummy_mount_path, disk_mount_manager_.unmounting_mount_paths()[0]);
+ disk_mount_manager_.NotifyUnmountDeviceComplete(MOUNT_ERROR_NONE);
+ EXPECT_EQ(0, fake_power_client_.GetNumPendingSuspendReadinessCallbacks());
+}
+
+TEST_F(SuspendUnmountManagerTest, CancelAndSuspendAgain) {
+ const std::string dummy_mount_path = "/dummy/mount";
+ disk_mount_manager_.CreateDiskEntryForMountDevice(
+ chromeos::disks::DiskMountManager::MountPointInfo(
+ "/dummy/device", dummy_mount_path, chromeos::MOUNT_TYPE_DEVICE,
+ chromeos::disks::MOUNT_CONDITION_NONE),
+ "device_id", "device_label", "Vendor", "Product",
+ chromeos::DEVICE_TYPE_USB, 1024 * 1024, true, true, true, false);
+ disk_mount_manager_.SetupDefaultReplies();
+ fake_power_client_.SendSuspendImminent();
+ EXPECT_EQ(1, fake_power_client_.GetNumPendingSuspendReadinessCallbacks());
+ ASSERT_EQ(1u, disk_mount_manager_.unmounting_mount_paths().size());
+ EXPECT_EQ(dummy_mount_path, disk_mount_manager_.unmounting_mount_paths()[0]);
+
+ // Suspend cancelled.
+ fake_power_client_.SendSuspendDone();
+
+ // Suspend again.
+ fake_power_client_.SendSuspendImminent();
+ ASSERT_EQ(2u, disk_mount_manager_.unmounting_mount_paths().size());
+ EXPECT_EQ(dummy_mount_path, disk_mount_manager_.unmounting_mount_paths()[1]);
+}
+
+} // namespace
+} // namespace chromeos
+} // namespace disks