diff options
author | hirono <hirono@chromium.org> | 2015-06-21 21:28:41 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-22 04:29:21 +0000 |
commit | 9f5eae54a21c440056afffc0b52fa3d07ae3f5eb (patch) | |
tree | bf5d33338ad4d4f343a25bd3944239755e41b5f9 | |
parent | 730e0fed9bd25d464fc85d67a34e778ae58c720e (diff) | |
download | chromium_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.gyp | 3 | ||||
-rw-r--r-- | chromeos/disks/disk_mount_manager.cc | 9 | ||||
-rw-r--r-- | chromeos/disks/suspend_unmount_manager.cc | 71 | ||||
-rw-r--r-- | chromeos/disks/suspend_unmount_manager.h | 54 | ||||
-rw-r--r-- | chromeos/disks/suspend_unmount_manager_unittest.cc | 91 |
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 |