Commit 9cf253d5 authored by Anand K. Mistry's avatar Anand K. Mistry Committed by Commit Bot

Files: Only unmount external media when enabling ExternalStorageDisabled

The policy is intended to unmount external media such as USB drives and
SD cards. However, cros-disks is now used to mount other types of file
systems such as DriveFS and sshfs for crostini. These don't count as
"external" and are covered by other policies.

Also, if an unmount fails, Chrome will keep trying to unmount the
device. Fix this by generating a list of mount points and iterating
through that list.

BUG=947375

Change-Id: I8a0813daa863e9f88e8cb1fc07cf8b7fc157a25d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1545956
Commit-Queue: Anand Mistry <amistry@chromium.org>
Reviewed-by: default avatarTatsuhisa Yamaguchi <yamaguchi@chromium.org>
Reviewed-by: default avatarSergei Datsenko <dats@chromium.org>
Cr-Commit-Position: refs/heads/master@{#647127}
parent 990e36dc
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "base/bind.h"
#include "chromeos/disks/disk.h" #include "chromeos/disks/disk.h"
namespace file_manager { namespace file_manager {
...@@ -103,20 +104,30 @@ void FakeDiskMountManager::UnmountPath(const std::string& mount_path, ...@@ -103,20 +104,30 @@ void FakeDiskMountManager::UnmountPath(const std::string& mount_path,
UnmountPathCallback callback) { UnmountPathCallback callback) {
unmount_requests_.emplace_back(mount_path, options); unmount_requests_.emplace_back(mount_path, options);
MountPointMap::iterator iter = mount_points_.find(mount_path); chromeos::MountError error = chromeos::MOUNT_ERROR_NONE;
if (iter == mount_points_.end()) auto unmount_iter = unmount_errors_.find(mount_path);
return; if (unmount_iter != unmount_errors_.end()) {
error = unmount_iter->second;
const MountPointInfo mount_point = iter->second; unmount_errors_.erase(unmount_iter);
mount_points_.erase(iter); } else {
for (auto& observer : observers_) { MountPointMap::iterator iter = mount_points_.find(mount_path);
observer.OnMountEvent(DiskMountManager::UNMOUNTING, if (iter == mount_points_.end())
chromeos::MOUNT_ERROR_NONE, mount_point); return;
const MountPointInfo mount_point = iter->second;
mount_points_.erase(iter);
for (auto& observer : observers_) {
observer.OnMountEvent(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE, mount_point);
}
} }
// Enqueue callback so that |FakeDiskMountManager::FinishAllUnmountRequest()| // Enqueue callback so that |FakeDiskMountManager::FinishAllUnmountRequest()|
// can call them. // can call them.
pending_unmount_callbacks_.push(std::move(callback)); if (callback) {
// Some tests pass a null |callback|.
pending_unmount_callbacks_.push(base::BindOnce(std::move(callback), error));
}
} }
void FakeDiskMountManager::RemountAllRemovableDrives( void FakeDiskMountManager::RemountAllRemovableDrives(
...@@ -129,13 +140,17 @@ bool FakeDiskMountManager::FinishAllUnmountPathRequests() { ...@@ -129,13 +140,17 @@ bool FakeDiskMountManager::FinishAllUnmountPathRequests() {
return false; return false;
while (!pending_unmount_callbacks_.empty()) { while (!pending_unmount_callbacks_.empty()) {
std::move(pending_unmount_callbacks_.front()) std::move(pending_unmount_callbacks_.front()).Run();
.Run(chromeos::MOUNT_ERROR_NONE);
pending_unmount_callbacks_.pop(); pending_unmount_callbacks_.pop();
} }
return true; return true;
} }
void FakeDiskMountManager::FailUnmountRequest(const std::string& mount_path,
chromeos::MountError error_code) {
unmount_errors_[mount_path] = error_code;
}
void FakeDiskMountManager::FormatMountedDevice(const std::string& mount_path) { void FakeDiskMountManager::FormatMountedDevice(const std::string& mount_path) {
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_FILE_MANAGER_FAKE_DISK_MOUNT_MANAGER_H_ #ifndef CHROME_BROWSER_CHROMEOS_FILE_MANAGER_FAKE_DISK_MOUNT_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_FILE_MANAGER_FAKE_DISK_MOUNT_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_FILE_MANAGER_FAKE_DISK_MOUNT_MANAGER_H_
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -70,6 +71,10 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager { ...@@ -70,6 +71,10 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager {
// otherwise. // otherwise.
bool FinishAllUnmountPathRequests(); bool FinishAllUnmountPathRequests();
// Fails a future unmount request for |mount_path| with |error_code|.
void FailUnmountRequest(const std::string& mount_path,
chromeos::MountError error_code);
// DiskMountManager overrides. // DiskMountManager overrides.
void AddObserver(Observer* observer) override; void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override;
...@@ -107,7 +112,7 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager { ...@@ -107,7 +112,7 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager {
private: private:
base::ObserverList<Observer>::Unchecked observers_; base::ObserverList<Observer>::Unchecked observers_;
base::queue<UnmountPathCallback> pending_unmount_callbacks_; base::queue<base::OnceClosure> pending_unmount_callbacks_;
DiskMap disks_; DiskMap disks_;
MountPointMap mount_points_; MountPointMap mount_points_;
...@@ -115,6 +120,7 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager { ...@@ -115,6 +120,7 @@ class FakeDiskMountManager : public chromeos::disks::DiskMountManager {
std::vector<MountRequest> mount_requests_; std::vector<MountRequest> mount_requests_;
std::vector<UnmountRequest> unmount_requests_; std::vector<UnmountRequest> unmount_requests_;
std::vector<RemountAllRequest> remount_all_requests_; std::vector<RemountAllRequest> remount_all_requests_;
std::map<std::string, chromeos::MountError> unmount_errors_;
DISALLOW_COPY_AND_ASSIGN(FakeDiskMountManager); DISALLOW_COPY_AND_ASSIGN(FakeDiskMountManager);
}; };
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -1050,17 +1051,28 @@ void VolumeManager::OnProvidedFileSystemUnmount( ...@@ -1050,17 +1051,28 @@ void VolumeManager::OnProvidedFileSystemUnmount(
} }
void VolumeManager::OnExternalStorageDisabledChangedUnmountCallback( void VolumeManager::OnExternalStorageDisabledChangedUnmountCallback(
std::vector<std::string> remaining_mount_paths,
chromeos::MountError error_code) { chromeos::MountError error_code) {
if (disk_mount_manager_->mount_points().empty()) LOG_IF(ERROR, error_code != chromeos::MOUNT_ERROR_NONE)
<< "Unmount on ExternalStorageDisabled policy change failed: "
<< error_code;
while (!remaining_mount_paths.empty()) {
std::string mount_path = remaining_mount_paths.back();
remaining_mount_paths.pop_back();
if (!base::ContainsKey(disk_mount_manager_->mount_points(), mount_path)) {
// The mount point could have already been removed for another reason
// (i.e. the disk was removed by the user).
continue;
}
disk_mount_manager_->UnmountPath(
mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
base::BindOnce(
&VolumeManager::OnExternalStorageDisabledChangedUnmountCallback,
weak_ptr_factory_.GetWeakPtr(), std::move(remaining_mount_paths)));
return; return;
// Repeat until unmount all paths }
const std::string& mount_path =
disk_mount_manager_->mount_points().begin()->second.mount_path;
disk_mount_manager_->UnmountPath(
mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
base::BindOnce(
&VolumeManager::OnExternalStorageDisabledChangedUnmountCallback,
weak_ptr_factory_.GetWeakPtr()));
} }
void VolumeManager::OnArcPlayStoreEnabledChanged(bool enabled) { void VolumeManager::OnArcPlayStoreEnabledChanged(bool enabled) {
...@@ -1107,17 +1119,26 @@ void VolumeManager::OnExternalStorageDisabledChanged() { ...@@ -1107,17 +1119,26 @@ void VolumeManager::OnExternalStorageDisabledChanged() {
// make it available. // make it available.
if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) { if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
// We do not iterate on mount_points directly, because mount_points can // We do not iterate on mount_points directly, because mount_points can
// be changed by UnmountPath(). // be changed by UnmountPath(). Also, a failing unmount shouldn't be retried
// TODO(hidehiko): Is it necessary to unmount mounted archives, too, here? // indefinitely. So make a set of all the mount points that should be
if (disk_mount_manager_->mount_points().empty()) // unmounted (all external media mounts), and iterate through them.
std::vector<std::string> remaining_mount_paths;
for (auto& mount_point : disk_mount_manager_->mount_points()) {
if (mount_point.second.mount_type == chromeos::MOUNT_TYPE_DEVICE) {
remaining_mount_paths.push_back(mount_point.first);
}
}
if (remaining_mount_paths.empty()) {
return; return;
const std::string& mount_path = }
disk_mount_manager_->mount_points().begin()->second.mount_path;
std::string mount_path = remaining_mount_paths.back();
remaining_mount_paths.pop_back();
disk_mount_manager_->UnmountPath( disk_mount_manager_->UnmountPath(
mount_path, chromeos::UNMOUNT_OPTIONS_NONE, mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
base::BindOnce( base::BindOnce(
&VolumeManager::OnExternalStorageDisabledChangedUnmountCallback, &VolumeManager::OnExternalStorageDisabledChangedUnmountCallback,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr(), std::move(remaining_mount_paths)));
} }
} }
......
...@@ -433,6 +433,7 @@ class VolumeManager : public KeyedService, ...@@ -433,6 +433,7 @@ class VolumeManager : public KeyedService,
std::unique_ptr<Volume> volume); std::unique_ptr<Volume> volume);
void DoUnmountEvent(chromeos::MountError error_code, const Volume& volume); void DoUnmountEvent(chromeos::MountError error_code, const Volume& volume);
void OnExternalStorageDisabledChangedUnmountCallback( void OnExternalStorageDisabledChangedUnmountCallback(
std::vector<std::string> remaining_mount_paths,
chromeos::MountError error_code); chromeos::MountError error_code);
// Returns the path of the mount point for drive. // Returns the path of the mount point for drive.
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include <set>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/drive/file_system_util.h"
...@@ -746,16 +748,24 @@ TEST_F(VolumeManagerTest, OnFormatEvent_CompletedFailed) { ...@@ -746,16 +748,24 @@ TEST_F(VolumeManagerTest, OnFormatEvent_CompletedFailed) {
} }
TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) { TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) {
// Here create two mount points. // Here create four mount points.
disk_mount_manager_->MountPath("mount1", "", "", {}, disk_mount_manager_->MountPath("mount1", "", "", {},
chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_TYPE_DEVICE,
chromeos::MOUNT_ACCESS_MODE_READ_WRITE); chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
disk_mount_manager_->MountPath("mount2", "", "", {}, disk_mount_manager_->MountPath("mount2", "", "", {},
chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_TYPE_DEVICE,
chromeos::MOUNT_ACCESS_MODE_READ_ONLY); chromeos::MOUNT_ACCESS_MODE_READ_ONLY);
disk_mount_manager_->MountPath("mount3", "", "", {},
chromeos::MOUNT_TYPE_NETWORK_STORAGE,
chromeos::MOUNT_ACCESS_MODE_READ_ONLY);
disk_mount_manager_->MountPath("failed_unmount", "", "", {},
chromeos::MOUNT_TYPE_DEVICE,
chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
disk_mount_manager_->FailUnmountRequest("failed_unmount",
chromeos::MOUNT_ERROR_UNKNOWN);
// Initially, there are two mount points. // Initially, there are four mount points.
ASSERT_EQ(2U, disk_mount_manager_->mount_points().size()); ASSERT_EQ(4U, disk_mount_manager_->mount_points().size());
ASSERT_EQ(0U, disk_mount_manager_->unmount_requests().size()); ASSERT_EQ(0U, disk_mount_manager_->unmount_requests().size());
// Emulate to set kExternalStorageDisabled to false. // Emulate to set kExternalStorageDisabled to false.
...@@ -763,7 +773,7 @@ TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) { ...@@ -763,7 +773,7 @@ TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) {
volume_manager()->OnExternalStorageDisabledChanged(); volume_manager()->OnExternalStorageDisabledChanged();
// Expect no effects. // Expect no effects.
EXPECT_EQ(2U, disk_mount_manager_->mount_points().size()); EXPECT_EQ(4U, disk_mount_manager_->mount_points().size());
EXPECT_EQ(0U, disk_mount_manager_->unmount_requests().size()); EXPECT_EQ(0U, disk_mount_manager_->unmount_requests().size());
// Emulate to set kExternalStorageDisabled to true. // Emulate to set kExternalStorageDisabled to true.
...@@ -774,17 +784,21 @@ TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) { ...@@ -774,17 +784,21 @@ TEST_F(VolumeManagerTest, OnExternalStorageDisabledChanged) {
// all the mount points will be invoked. // all the mount points will be invoked.
disk_mount_manager_->FinishAllUnmountPathRequests(); disk_mount_manager_->FinishAllUnmountPathRequests();
// The all mount points should be unmounted. // The external media mount points should be unmounted. Other mount point
EXPECT_EQ(0U, disk_mount_manager_->mount_points().size()); // types should remain. The failing unmount should also remain.
EXPECT_EQ(2U, disk_mount_manager_->mount_points().size());
EXPECT_EQ(2U, disk_mount_manager_->unmount_requests().size());
const FakeDiskMountManager::UnmountRequest& unmount_request1 =
disk_mount_manager_->unmount_requests()[0];
EXPECT_EQ("mount1", unmount_request1.mount_path);
const FakeDiskMountManager::UnmountRequest& unmount_request2 = std::set<std::string> expected_unmount_requests = {
disk_mount_manager_->unmount_requests()[1]; "mount1",
EXPECT_EQ("mount2", unmount_request2.mount_path); "mount2",
"failed_unmount",
};
for (const auto& request : disk_mount_manager_->unmount_requests()) {
EXPECT_TRUE(
base::ContainsKey(expected_unmount_requests, request.mount_path));
expected_unmount_requests.erase(request.mount_path);
}
EXPECT_TRUE(expected_unmount_requests.empty());
} }
TEST_F(VolumeManagerTest, ExternalStorageDisabledPolicyMultiProfile) { TEST_F(VolumeManagerTest, ExternalStorageDisabledPolicyMultiProfile) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment