summaryrefslogtreecommitdiffstats
path: root/chromeos/disks
diff options
context:
space:
mode:
authorhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-26 12:02:39 +0000
committerhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-26 12:02:39 +0000
commit4cbead4315188994d0554984777e0c21115f22c0 (patch)
tree93a33939223e27ad3954767dfb6b7dc7c5b68c95 /chromeos/disks
parent0518d0dde990e5382c94bde61e10cd3f3bbf7c27 (diff)
downloadchromium_src-4cbead4315188994d0554984777e0c21115f22c0.zip
chromium_src-4cbead4315188994d0554984777e0c21115f22c0.tar.gz
chromium_src-4cbead4315188994d0554984777e0c21115f22c0.tar.bz2
chromeos: Move src/chrome/browser/chromeos/disks to src/chromeos
GetSizeStatsOnFileThread is moved from disk_mount_manager.cc to file_browser_private_api.cc BUG=None TEST=build TBR=estade@chromium.org, kaznacheev@chromium.org Review URL: https://chromiumcodereview.appspot.com/10874067 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153402 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/disks')
-rw-r--r--chromeos/disks/disk_mount_manager.cc674
-rw-r--r--chromeos/disks/disk_mount_manager.h267
-rw-r--r--chromeos/disks/mock_disk_mount_manager.cc227
-rw-r--r--chromeos/disks/mock_disk_mount_manager.h101
4 files changed, 1269 insertions, 0 deletions
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc
new file mode 100644
index 0000000..828cebb
--- /dev/null
+++ b/chromeos/disks/disk_mount_manager.cc
@@ -0,0 +1,674 @@
+// Copyright (c) 2012 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/disk_mount_manager.h"
+
+#include <map>
+#include <set>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/string_util.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+
+namespace chromeos {
+namespace disks {
+
+namespace {
+
+const char kDeviceNotFound[] = "Device could not be found";
+
+DiskMountManager* g_disk_mount_manager = NULL;
+
+// The DiskMountManager implementation.
+class DiskMountManagerImpl : public DiskMountManager {
+ public:
+ DiskMountManagerImpl() : 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_);
+
+ cros_disks_client_->SetUpConnections(
+ base::Bind(&DiskMountManagerImpl::OnMountEvent,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&DiskMountManagerImpl::OnMountCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ virtual ~DiskMountManagerImpl() {
+ }
+
+ // DiskMountManager override.
+ virtual void AddObserver(Observer* observer) OVERRIDE {
+ observers_.AddObserver(observer);
+ }
+
+ // DiskMountManager override.
+ virtual void RemoveObserver(Observer* observer) OVERRIDE {
+ observers_.RemoveObserver(observer);
+ }
+
+ // DiskMountManager override.
+ virtual void MountPath(const std::string& source_path,
+ const std::string& source_format,
+ const std::string& mount_label,
+ MountType type) OVERRIDE {
+ // Hidden and non-existent devices should not be mounted.
+ if (type == MOUNT_TYPE_DEVICE) {
+ DiskMap::const_iterator it = disks_.find(source_path);
+ if (it == disks_.end() || it->second->is_hidden()) {
+ OnMountCompleted(MOUNT_ERROR_INTERNAL, source_path, type, "");
+ return;
+ }
+ }
+ cros_disks_client_->Mount(
+ source_path,
+ source_format,
+ mount_label,
+ type,
+ // When succeeds, OnMountCompleted will be called by
+ // "MountCompleted" signal instead.
+ base::Bind(&base::DoNothing),
+ base::Bind(&DiskMountManagerImpl::OnMountCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ MOUNT_ERROR_INTERNAL,
+ source_path,
+ type,
+ ""));
+ }
+
+ // DiskMountManager override.
+ virtual void UnmountPath(const std::string& mount_path) OVERRIDE {
+ cros_disks_client_->Unmount(mount_path,
+ base::Bind(&DiskMountManagerImpl::OnUnmountPath,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+
+ // DiskMountManager override.
+ virtual void FormatUnmountedDevice(const std::string& file_path) OVERRIDE {
+ for (DiskMountManager::DiskMap::iterator it = disks_.begin();
+ it != disks_.end(); ++it) {
+ if (it->second->file_path() == file_path &&
+ !it->second->mount_path().empty()) {
+ LOG(ERROR) << "Device is still mounted: " << file_path;
+ OnFormatDevice(file_path, false);
+ return;
+ }
+ }
+ const char kFormatVFAT[] = "vfat";
+ cros_disks_client_->FormatDevice(
+ file_path,
+ kFormatVFAT,
+ base::Bind(&DiskMountManagerImpl::OnFormatDevice,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&DiskMountManagerImpl::OnFormatDevice,
+ weak_ptr_factory_.GetWeakPtr(),
+ file_path,
+ false));
+ }
+
+ // DiskMountManager override.
+ virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE {
+ Disk* disk = NULL;
+ for (DiskMountManager::DiskMap::iterator it = disks_.begin();
+ it != disks_.end(); ++it) {
+ if (it->second->mount_path() == mount_path) {
+ disk = it->second;
+ break;
+ }
+ }
+ if (!disk) {
+ LOG(ERROR) << "Device with this mount path not found: " << mount_path;
+ OnFormatDevice(mount_path, false);
+ return;
+ }
+ if (formatting_pending_.find(disk->device_path()) !=
+ formatting_pending_.end()) {
+ LOG(ERROR) << "Formatting is already pending: " << mount_path;
+ OnFormatDevice(mount_path, false);
+ return;
+ }
+ // Formatting process continues, after unmounting.
+ formatting_pending_[disk->device_path()] = disk->file_path();
+ UnmountPath(disk->mount_path());
+ }
+
+ // DiskMountManager override.
+ virtual void UnmountDeviceRecursive(
+ const std::string& device_path,
+ UnmountDeviceRecursiveCallbackType callback,
+ void* user_data) OVERRIDE {
+ bool success = true;
+ std::string error_message;
+ std::vector<std::string> devices_to_unmount;
+
+ // Get list of all devices to unmount.
+ int device_path_len = device_path.length();
+ for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) {
+ if (!it->second->mount_path().empty() &&
+ strncmp(device_path.c_str(), it->second->device_path().c_str(),
+ device_path_len) == 0) {
+ devices_to_unmount.push_back(it->second->mount_path());
+ }
+ }
+ // We should detect at least original device.
+ if (devices_to_unmount.empty()) {
+ if (disks_.find(device_path) == disks_.end()) {
+ success = false;
+ error_message = kDeviceNotFound;
+ } else {
+ // Nothing to unmount.
+ callback(user_data, true);
+ return;
+ }
+ }
+ if (success) {
+ // We will send the same callback data object to all Unmount calls and use
+ // it to syncronize callbacks.
+ UnmountDeviceRecursiveCallbackData* cb_data =
+ new UnmountDeviceRecursiveCallbackData(user_data, callback,
+ devices_to_unmount.size());
+ for (size_t i = 0; i < devices_to_unmount.size(); ++i) {
+ cros_disks_client_->Unmount(
+ devices_to_unmount[i],
+ base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursive,
+ weak_ptr_factory_.GetWeakPtr(), cb_data, true),
+ base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursive,
+ weak_ptr_factory_.GetWeakPtr(),
+ cb_data,
+ false,
+ devices_to_unmount[i]));
+ }
+ } else {
+ LOG(WARNING) << "Unmount recursive request failed for device "
+ << device_path << ", with error: " << error_message;
+ callback(user_data, false);
+ }
+ }
+
+ // DiskMountManager override.
+ virtual void RequestMountInfoRefresh() OVERRIDE {
+ cros_disks_client_->EnumerateAutoMountableDevices(
+ base::Bind(&DiskMountManagerImpl::OnRequestMountInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+
+ // DiskMountManager override.
+ const DiskMap& disks() const OVERRIDE { return disks_; }
+
+ // DiskMountManager override.
+ virtual const Disk* FindDiskBySourcePath(const std::string& source_path)
+ const OVERRIDE {
+ DiskMap::const_iterator disk_it = disks_.find(source_path);
+ return disk_it == disks_.end() ? NULL : disk_it->second;
+ }
+
+ // DiskMountManager override.
+ const MountPointMap& mount_points() const OVERRIDE { return mount_points_; }
+
+ private:
+ struct UnmountDeviceRecursiveCallbackData {
+ void* user_data;
+ UnmountDeviceRecursiveCallbackType callback;
+ size_t pending_callbacks_count;
+
+ UnmountDeviceRecursiveCallbackData(void* ud,
+ UnmountDeviceRecursiveCallbackType cb,
+ int count)
+ : user_data(ud),
+ callback(cb),
+ pending_callbacks_count(count) {
+ }
+ };
+
+ // Callback for UnmountDeviceRecursive.
+ void OnUnmountDeviceRecursive(UnmountDeviceRecursiveCallbackData* cb_data,
+ bool success,
+ const std::string& mount_path) {
+ if (success) {
+ // Do standard processing for Unmount event.
+ OnUnmountPath(mount_path);
+ LOG(INFO) << mount_path << " unmounted.";
+ }
+ // This is safe as long as all callbacks are called on the same thread as
+ // UnmountDeviceRecursive.
+ cb_data->pending_callbacks_count--;
+
+ if (cb_data->pending_callbacks_count == 0) {
+ cb_data->callback(cb_data->user_data, success);
+ delete cb_data;
+ }
+ }
+
+ // Callback to handle MountCompleted signal and Mount method call failure.
+ void OnMountCompleted(MountError error_code,
+ const std::string& source_path,
+ MountType mount_type,
+ const std::string& mount_path) {
+ MountCondition mount_condition = MOUNT_CONDITION_NONE;
+ if (mount_type == MOUNT_TYPE_DEVICE) {
+ if (error_code == MOUNT_ERROR_UNKNOWN_FILESYSTEM) {
+ mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM;
+ }
+ if (error_code == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM) {
+ mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM;
+ }
+ }
+ const MountPointInfo mount_info(source_path, mount_path, mount_type,
+ mount_condition);
+
+ NotifyMountCompleted(MOUNTING, error_code, mount_info);
+
+ // If the device is corrupted but it's still possible to format it, it will
+ // be fake mounted.
+ if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) &&
+ mount_points_.find(mount_info.mount_path) == mount_points_.end()) {
+ mount_points_.insert(MountPointMap::value_type(mount_info.mount_path,
+ mount_info));
+ }
+ if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) &&
+ mount_info.mount_type == MOUNT_TYPE_DEVICE &&
+ !mount_info.source_path.empty() &&
+ !mount_info.mount_path.empty()) {
+ DiskMap::iterator iter = disks_.find(mount_info.source_path);
+ if (iter == disks_.end()) {
+ // disk might have been removed by now?
+ return;
+ }
+ Disk* disk = iter->second;
+ DCHECK(disk);
+ disk->set_mount_path(mount_info.mount_path);
+ NotifyDiskStatusUpdate(MOUNT_DISK_MOUNTED, disk);
+ }
+ }
+
+ // Callback for UnmountPath.
+ void OnUnmountPath(const std::string& mount_path) {
+ MountPointMap::iterator mount_points_it = mount_points_.find(mount_path);
+ if (mount_points_it == mount_points_.end())
+ return;
+ // TODO(tbarzic): Add separate, PathUnmounted event to Observer.
+ NotifyMountCompleted(
+ UNMOUNTING, MOUNT_ERROR_NONE,
+ MountPointInfo(mount_points_it->second.source_path,
+ mount_points_it->second.mount_path,
+ mount_points_it->second.mount_type,
+ mount_points_it->second.mount_condition));
+ std::string path(mount_points_it->second.source_path);
+ mount_points_.erase(mount_points_it);
+ DiskMap::iterator iter = disks_.find(path);
+ if (iter == disks_.end()) {
+ // disk might have been removed by now.
+ return;
+ }
+ Disk* disk = iter->second;
+ DCHECK(disk);
+ disk->clear_mount_path();
+ // Check if there is a formatting scheduled.
+ PathMap::iterator it = formatting_pending_.find(disk->device_path());
+ if (it != formatting_pending_.end()) {
+ // Copy the string before it gets erased.
+ const std::string file_path = it->second;
+ formatting_pending_.erase(it);
+ FormatUnmountedDevice(file_path);
+ }
+ }
+
+ // Callback for FormatDevice.
+ void OnFormatDevice(const std::string& device_path, bool success) {
+ if (success) {
+ NotifyDeviceStatusUpdate(MOUNT_FORMATTING_STARTED, device_path);
+ } else {
+ NotifyDeviceStatusUpdate(MOUNT_FORMATTING_STARTED,
+ std::string("!") + device_path);
+ LOG(WARNING) << "Format request failed for device " << device_path;
+ }
+ }
+
+ // Callbcak for GetDeviceProperties.
+ void OnGetDeviceProperties(const DiskInfo& disk_info) {
+ // TODO(zelidrag): Find a better way to filter these out before we
+ // fetch the properties:
+ // Ignore disks coming from the device we booted the system from.
+ if (disk_info.on_boot_device())
+ return;
+
+ LOG(WARNING) << "Found disk " << disk_info.device_path();
+ // Delete previous disk info for this path:
+ bool is_new = true;
+ DiskMap::iterator iter = disks_.find(disk_info.device_path());
+ if (iter != disks_.end()) {
+ delete iter->second;
+ disks_.erase(iter);
+ is_new = false;
+ }
+ Disk* disk = new Disk(disk_info.device_path(),
+ disk_info.mount_path(),
+ disk_info.system_path(),
+ disk_info.file_path(),
+ disk_info.label(),
+ disk_info.drive_label(),
+ disk_info.uuid(),
+ FindSystemPathPrefix(disk_info.system_path()),
+ disk_info.device_type(),
+ disk_info.total_size_in_bytes(),
+ disk_info.is_drive(),
+ disk_info.is_read_only(),
+ disk_info.has_media(),
+ disk_info.on_boot_device(),
+ disk_info.is_hidden());
+ disks_.insert(std::make_pair(disk_info.device_path(), disk));
+ NotifyDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED,
+ disk);
+ }
+
+ // Callbcak for RequestMountInfo.
+ void OnRequestMountInfo(const std::vector<std::string>& devices) {
+ std::set<std::string> current_device_set;
+ if (!devices.empty()) {
+ // Initiate properties fetch for all removable disks,
+ for (size_t i = 0; i < devices.size(); i++) {
+ current_device_set.insert(devices[i]);
+ // Initiate disk property retrieval for each relevant device path.
+ cros_disks_client_->GetDeviceProperties(
+ devices[i],
+ base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+ }
+ // Search and remove disks that are no longer present.
+ for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) {
+ if (current_device_set.find(iter->first) == current_device_set.end()) {
+ Disk* disk = iter->second;
+ NotifyDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
+ delete iter->second;
+ disks_.erase(iter++);
+ } else {
+ ++iter;
+ }
+ }
+ }
+
+ // Callback to handle mount event signals.
+ void OnMountEvent(MountEventType event, const std::string& device_path_arg) {
+ // Take a copy of the argument so we can modify it below.
+ std::string device_path = device_path_arg;
+ DiskMountManagerEventType type = MOUNT_DEVICE_ADDED;
+ switch (event) {
+ case DISK_ADDED: {
+ cros_disks_client_->GetDeviceProperties(
+ device_path,
+ base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ return;
+ }
+ case DISK_REMOVED: {
+ // Search and remove disks that are no longer present.
+ DiskMountManager::DiskMap::iterator iter = disks_.find(device_path);
+ if (iter != disks_.end()) {
+ Disk* disk = iter->second;
+ NotifyDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
+ delete iter->second;
+ disks_.erase(iter);
+ }
+ return;
+ }
+ case DEVICE_ADDED: {
+ type = MOUNT_DEVICE_ADDED;
+ system_path_prefixes_.insert(device_path);
+ break;
+ }
+ case DEVICE_REMOVED: {
+ type = MOUNT_DEVICE_REMOVED;
+ system_path_prefixes_.erase(device_path);
+ break;
+ }
+ case DEVICE_SCANNED: {
+ type = MOUNT_DEVICE_SCANNED;
+ break;
+ }
+ case FORMATTING_FINISHED: {
+ // FORMATTING_FINISHED actually returns file path instead of device
+ // path.
+ device_path = FilePathToDevicePath(device_path);
+ if (device_path.empty()) {
+ LOG(ERROR) << "Error while handling disks metadata. Cannot find "
+ << "device that is being formatted.";
+ return;
+ }
+ type = MOUNT_FORMATTING_FINISHED;
+ break;
+ }
+ default: {
+ LOG(ERROR) << "Unknown event: " << event;
+ return;
+ }
+ }
+ NotifyDeviceStatusUpdate(type, device_path);
+ }
+
+ // Notifies all observers about disk status update.
+ void NotifyDiskStatusUpdate(DiskMountManagerEventType event,
+ const Disk* disk) {
+ FOR_EACH_OBSERVER(Observer, observers_, DiskChanged(event, disk));
+ }
+
+ // Notifies all observers about device status update.
+ void NotifyDeviceStatusUpdate(DiskMountManagerEventType event,
+ const std::string& device_path) {
+ FOR_EACH_OBSERVER(Observer, observers_, DeviceChanged(event, device_path));
+ }
+
+ // Notifies all observers about mount completion.
+ void NotifyMountCompleted(MountEvent event_type,
+ MountError error_code,
+ const MountPointInfo& mount_info) {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ MountCompleted(event_type, error_code, mount_info));
+ }
+
+ // Converts file path to device path.
+ std::string FilePathToDevicePath(const std::string& file_path) {
+ // TODO(hashimoto): Refactor error handling code like here.
+ // Appending "!" is not the best way to indicate error. This kind of trick
+ // also makes it difficult to simplify the code paths. crosbug.com/22972
+ const int failed = StartsWithASCII(file_path, "!", true);
+ for (DiskMountManager::DiskMap::iterator it = disks_.begin();
+ it != disks_.end(); ++it) {
+ // Skip the leading '!' on the failure case.
+ if (it->second->file_path() == file_path.substr(failed)) {
+ if (failed)
+ return std::string("!") + it->second->device_path();
+ else
+ return it->second->device_path();
+ }
+ }
+ return "";
+ }
+
+ // Finds system path prefix from |system_path|.
+ const std::string& FindSystemPathPrefix(const std::string& system_path) {
+ if (system_path.empty())
+ return EmptyString();
+ for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin();
+ it != system_path_prefixes_.end();
+ ++it) {
+ const std::string& prefix = *it;
+ if (StartsWithASCII(system_path, prefix, true))
+ return prefix;
+ }
+ return EmptyString();
+ }
+
+ // Mount event change observers.
+ ObserverList<Observer> observers_;
+
+ CrosDisksClient* cros_disks_client_;
+
+ // The list of disks found.
+ DiskMountManager::DiskMap disks_;
+
+ DiskMountManager::MountPointMap mount_points_;
+
+ typedef std::set<std::string> SystemPathPrefixSet;
+ SystemPathPrefixSet system_path_prefixes_;
+
+ // A map from device path (e.g. /sys/devices/pci0000:00/.../sdb/sdb1)) to file
+ // path (e.g. /dev/sdb).
+ // Devices in this map are supposed to be formatted, but are currently waiting
+ // to be unmounted. When device is in this map, the formatting process HAVEN'T
+ // started yet.
+ typedef std::map<std::string, std::string> PathMap;
+ PathMap formatting_pending_;
+
+ base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl);
+};
+
+} // namespace
+
+DiskMountManager::Disk::Disk(const std::string& device_path,
+ const std::string& mount_path,
+ const std::string& system_path,
+ const std::string& file_path,
+ const std::string& device_label,
+ const std::string& drive_label,
+ const std::string& fs_uuid,
+ const std::string& system_path_prefix,
+ DeviceType device_type,
+ uint64 total_size_in_bytes,
+ bool is_parent,
+ bool is_read_only,
+ bool has_media,
+ bool on_boot_device,
+ bool is_hidden)
+ : device_path_(device_path),
+ mount_path_(mount_path),
+ system_path_(system_path),
+ file_path_(file_path),
+ device_label_(device_label),
+ drive_label_(drive_label),
+ fs_uuid_(fs_uuid),
+ system_path_prefix_(system_path_prefix),
+ device_type_(device_type),
+ total_size_in_bytes_(total_size_in_bytes),
+ is_parent_(is_parent),
+ is_read_only_(is_read_only),
+ has_media_(has_media),
+ on_boot_device_(on_boot_device),
+ is_hidden_(is_hidden) {
+}
+
+DiskMountManager::Disk::~Disk() {}
+
+// static
+std::string DiskMountManager::MountTypeToString(MountType type) {
+ switch (type) {
+ case MOUNT_TYPE_DEVICE:
+ return "device";
+ case MOUNT_TYPE_ARCHIVE:
+ return "file";
+ case MOUNT_TYPE_NETWORK_STORAGE:
+ return "network";
+ case MOUNT_TYPE_GDATA:
+ return "gdata";
+ case MOUNT_TYPE_INVALID:
+ return "invalid";
+ default:
+ NOTREACHED();
+ }
+ return "";
+}
+
+// static
+std::string DiskMountManager::MountConditionToString(MountCondition condition) {
+ switch (condition) {
+ case MOUNT_CONDITION_NONE:
+ return "";
+ case MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
+ return "unknown_filesystem";
+ case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
+ return "unsupported_filesystem";
+ default:
+ NOTREACHED();
+ }
+ return "";
+}
+
+// static
+MountType DiskMountManager::MountTypeFromString(const std::string& type_str) {
+ if (type_str == "device")
+ return MOUNT_TYPE_DEVICE;
+ else if (type_str == "network")
+ return MOUNT_TYPE_NETWORK_STORAGE;
+ else if (type_str == "file")
+ return MOUNT_TYPE_ARCHIVE;
+ else if (type_str == "gdata")
+ return MOUNT_TYPE_GDATA;
+ else
+ return MOUNT_TYPE_INVALID;
+}
+
+// static
+std::string DiskMountManager::DeviceTypeToString(DeviceType type) {
+ switch (type) {
+ case DEVICE_TYPE_USB:
+ return "usb";
+ case DEVICE_TYPE_SD:
+ return "sd";
+ case DEVICE_TYPE_OPTICAL_DISC:
+ return "optical";
+ case DEVICE_TYPE_MOBILE:
+ return "mobile";
+ default:
+ return "unknown";
+ }
+}
+
+// static
+void DiskMountManager::Initialize() {
+ if (g_disk_mount_manager) {
+ LOG(WARNING) << "DiskMountManager was already initialized";
+ return;
+ }
+ g_disk_mount_manager = new DiskMountManagerImpl();
+ VLOG(1) << "DiskMountManager initialized";
+}
+
+// static
+void DiskMountManager::InitializeForTesting(
+ DiskMountManager* disk_mount_manager) {
+ if (g_disk_mount_manager) {
+ LOG(WARNING) << "DiskMountManager was already initialized";
+ return;
+ }
+ g_disk_mount_manager = disk_mount_manager;
+ VLOG(1) << "DiskMountManager initialized";
+}
+
+// static
+void DiskMountManager::Shutdown() {
+ if (!g_disk_mount_manager) {
+ LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager";
+ return;
+ }
+ delete g_disk_mount_manager;
+ g_disk_mount_manager = NULL;
+ VLOG(1) << "DiskMountManager Shutdown completed";
+}
+
+// static
+DiskMountManager* DiskMountManager::GetInstance() {
+ return g_disk_mount_manager;
+}
+
+} // namespace disks
+} // namespace chromeos
diff --git a/chromeos/disks/disk_mount_manager.h b/chromeos/disks/disk_mount_manager.h
new file mode 100644
index 0000000..dfe80c3
--- /dev/null
+++ b/chromeos/disks/disk_mount_manager.h
@@ -0,0 +1,267 @@
+// Copyright (c) 2012 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_DISK_MOUNT_MANAGER_H_
+#define CHROMEOS_DISKS_DISK_MOUNT_MANAGER_H_
+
+#include <map>
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/cros_disks_client.h"
+
+namespace chromeos {
+namespace disks {
+
+// Types of events DiskMountManager sends to its observers.
+enum DiskMountManagerEventType {
+ MOUNT_DISK_ADDED,
+ MOUNT_DISK_REMOVED,
+ MOUNT_DISK_CHANGED,
+ MOUNT_DISK_MOUNTED,
+ MOUNT_DISK_UNMOUNTED,
+ MOUNT_DEVICE_ADDED,
+ MOUNT_DEVICE_REMOVED,
+ MOUNT_DEVICE_SCANNED,
+ MOUNT_FORMATTING_STARTED,
+ MOUNT_FORMATTING_FINISHED,
+};
+
+// Condition of mounted filesystem.
+enum MountCondition {
+ MOUNT_CONDITION_NONE,
+ MOUNT_CONDITION_UNKNOWN_FILESYSTEM,
+ MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM,
+};
+
+// This class handles the interaction with cros-disks.
+// Other classes can add themselves as observers.
+class CHROMEOS_EXPORT DiskMountManager {
+ public:
+ // Event type given to observers' MountCompleted method.
+ enum MountEvent {
+ MOUNTING,
+ UNMOUNTING,
+ };
+
+ // Used to house an instance of each found mount device.
+ class Disk {
+ public:
+ Disk(const std::string& device_path,
+ const std::string& mount_path,
+ const std::string& system_path,
+ const std::string& file_path,
+ const std::string& device_label,
+ const std::string& drive_label,
+ const std::string& fs_uuid,
+ const std::string& system_path_prefix,
+ DeviceType device_type,
+ uint64 total_size_in_bytes,
+ bool is_parent,
+ bool is_read_only,
+ bool has_media,
+ bool on_boot_device,
+ bool is_hidden);
+ ~Disk();
+
+ // The path of the device, used by devicekit-disks.
+ // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/block/sdb/sdb1)
+ const std::string& device_path() const { return device_path_; }
+
+ // The path to the mount point of this device. Will be empty if not mounted.
+ // (e.g. /media/removable/VOLUME)
+ const std::string& mount_path() const { return mount_path_; }
+
+ // The path of the device according to the udev system.
+ // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/block/sdb/sdb1)
+ const std::string& system_path() const { return system_path_; }
+
+ // The path of the device according to filesystem.
+ // (e.g. /dev/sdb)
+ const std::string& file_path() const { return file_path_; }
+
+ // Device's label.
+ const std::string& device_label() const { return device_label_; }
+
+ // If disk is a parent, then its label, else parents label.
+ // (e.g. "TransMemory")
+ const std::string& drive_label() const { return drive_label_; }
+
+ // Returns the file system uuid string.
+ const std::string& fs_uuid() const { return fs_uuid_; }
+
+ // Path of the system device this device's block is a part of.
+ // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/)
+ const std::string& system_path_prefix() const {
+ return system_path_prefix_;
+ }
+
+ // Device type.
+ DeviceType device_type() const { return device_type_; }
+
+ // Total size of the device in bytes.
+ uint64 total_size_in_bytes() const { return total_size_in_bytes_; }
+
+ // Is the device is a parent device (i.e. sdb rather than sdb1).
+ bool is_parent() const { return is_parent_; }
+
+ // Is the device read only.
+ bool is_read_only() const { return is_read_only_; }
+
+ // Does the device contains media.
+ bool has_media() const { return has_media_; }
+
+ // Is the device on the boot device.
+ bool on_boot_device() const { return on_boot_device_; }
+
+ // Shoud the device be shown in the UI, or automounted.
+ bool is_hidden() const { return is_hidden_; }
+
+ void set_mount_path(const std::string& mount_path) {
+ mount_path_ = mount_path;
+ }
+
+ void clear_mount_path() { mount_path_.clear(); }
+
+ private:
+ std::string device_path_;
+ std::string mount_path_;
+ std::string system_path_;
+ std::string file_path_;
+ std::string device_label_;
+ std::string drive_label_;
+ std::string fs_uuid_;
+ std::string system_path_prefix_;
+ DeviceType device_type_;
+ uint64 total_size_in_bytes_;
+ bool is_parent_;
+ bool is_read_only_;
+ bool has_media_;
+ bool on_boot_device_;
+ bool is_hidden_;
+ };
+ typedef std::map<std::string, Disk*> DiskMap;
+
+ // A struct to store information about mount point.
+ struct MountPointInfo {
+ // Device's path.
+ std::string source_path;
+ // Mounted path.
+ std::string mount_path;
+ // Type of mount.
+ MountType mount_type;
+ // Condition of mount.
+ MountCondition mount_condition;
+
+ MountPointInfo(const std::string& source,
+ const std::string& mount,
+ const MountType type,
+ MountCondition condition)
+ : source_path(source),
+ mount_path(mount),
+ mount_type(type),
+ mount_condition(condition) {
+ }
+ };
+
+ // MountPointMap key is mount_path.
+ typedef std::map<std::string, MountPointInfo> MountPointMap;
+
+ // A callback function type which is called after UnmountDeviceRecursive
+ // finishes.
+ typedef void(*UnmountDeviceRecursiveCallbackType)(void*, bool);
+
+ // Implement this interface to be notified about disk/mount related events.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // A function called when disk mount status is changed.
+ virtual void DiskChanged(DiskMountManagerEventType event,
+ const Disk* disk) = 0;
+ // A function called when device status is changed.
+ virtual void DeviceChanged(DiskMountManagerEventType event,
+ const std::string& device_path) = 0;
+ // A function called after mount is completed.
+ virtual void MountCompleted(MountEvent event_type,
+ MountError error_code,
+ const MountPointInfo& mount_info) = 0;
+ };
+
+ virtual ~DiskMountManager() {}
+
+ // Adds an observer.
+ virtual void AddObserver(Observer* observer) = 0;
+
+ // Removes an observer.
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Gets the list of disks found.
+ virtual const DiskMap& disks() const = 0;
+
+ // Returns Disk object corresponding to |source_path| or NULL on failure.
+ virtual const Disk* FindDiskBySourcePath(
+ const std::string& source_path) const = 0;
+
+ // Gets the list of mount points.
+ virtual const MountPointMap& mount_points() const = 0;
+
+ // Requests refreshing all the information about mounted disks.
+ virtual void RequestMountInfoRefresh() = 0;
+
+ // Mounts a device.
+ virtual void MountPath(const std::string& source_path,
+ const std::string& source_format,
+ const std::string& mount_label,
+ MountType type) = 0;
+
+ // Unmounts a mounted disk.
+ virtual void UnmountPath(const std::string& mount_path) = 0;
+
+ // Formats device given its file path.
+ // Example: file_path: /dev/sdb1
+ virtual void FormatUnmountedDevice(const std::string& file_path) = 0;
+
+ // Formats Device given its mount path. Unmounts the device.
+ // Example: mount_path: /media/VOLUME_LABEL
+ virtual void FormatMountedDevice(const std::string& mount_path) = 0;
+
+ // Unmounts device_path and all of its known children.
+ virtual void UnmountDeviceRecursive(
+ const std::string& device_path,
+ UnmountDeviceRecursiveCallbackType callback,
+ void* user_data) = 0;
+
+ // Returns corresponding string to |type| like "device" or "file".
+ static std::string MountTypeToString(MountType type);
+
+ // The inverse function of MountTypeToString.
+ static MountType MountTypeFromString(const std::string& type_str);
+
+ // Returns corresponding string to |type| like "unknown_filesystem".
+ static std::string MountConditionToString(MountCondition type);
+
+ // Returns corresponding string to |type|, like "sd", "usb".
+ static std::string DeviceTypeToString(DeviceType type);
+
+ // Creates the global DiskMountManager instance.
+ static void Initialize();
+
+ // Similar to Initialize(), but can inject an alternative
+ // DiskMountManager such as MockDiskMountManager for testing.
+ // The injected object will be owned by the internal pointer and deleted
+ // by Shutdown().
+ static void InitializeForTesting(DiskMountManager* disk_mount_manager);
+
+ // Destroys the global DiskMountManager instance if it exists.
+ static void Shutdown();
+
+ // Returns a pointer to the global DiskMountManager instance.
+ // Initialize() should already have been called.
+ static DiskMountManager* GetInstance();
+};
+
+} // namespace disks
+} // namespace chromeos
+
+#endif // CHROMEOS_DISKS_DISK_MOUNT_MANAGER_H_
diff --git a/chromeos/disks/mock_disk_mount_manager.cc b/chromeos/disks/mock_disk_mount_manager.cc
new file mode 100644
index 0000000..0b67c9a
--- /dev/null
+++ b/chromeos/disks/mock_disk_mount_manager.cc
@@ -0,0 +1,227 @@
+// Copyright (c) 2012 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/mock_disk_mount_manager.h"
+
+#include <utility>
+
+#include "base/message_loop.h"
+#include "base/stl_util.h"
+#include "base/string_util.h"
+
+using testing::_;
+using testing::AnyNumber;
+using testing::Invoke;
+using testing::ReturnRef;
+
+namespace chromeos {
+namespace disks {
+
+namespace {
+
+const char* kTestSystemPath = "/this/system/path";
+const char* kTestSystemPathPrefix = "/this/system";
+const char* kTestDevicePath = "/this/device/path";
+const char* kTestMountPath = "/media/foofoo";
+const char* kTestFilePath = "/this/file/path";
+const char* kTestDeviceLabel = "A label";
+const char* kTestDriveLabel = "Another label";
+const char* kTestUuid = "FFFF-FFFF";
+
+} // namespace
+
+void MockDiskMountManager::AddObserverInternal(
+ DiskMountManager::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void MockDiskMountManager::RemoveObserverInternal(
+ DiskMountManager::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+MockDiskMountManager::MockDiskMountManager() {
+ ON_CALL(*this, AddObserver(_))
+ .WillByDefault(Invoke(this, &MockDiskMountManager::AddObserverInternal));
+ ON_CALL(*this, RemoveObserver(_))
+ .WillByDefault(Invoke(this,
+ &MockDiskMountManager::RemoveObserverInternal));
+ ON_CALL(*this, disks())
+ .WillByDefault(Invoke(this, &MockDiskMountManager::disksInternal));
+ ON_CALL(*this, mount_points())
+ .WillByDefault(Invoke(this, &MockDiskMountManager::mountPointsInternal));
+ ON_CALL(*this, FindDiskBySourcePath(_))
+ .WillByDefault(Invoke(
+ this, &MockDiskMountManager::FindDiskBySourcePathInternal));
+}
+
+MockDiskMountManager::~MockDiskMountManager() {
+ STLDeleteContainerPairSecondPointers(disks_.begin(), disks_.end());
+ disks_.clear();
+}
+
+void MockDiskMountManager::NotifyDeviceInsertEvents() {
+ scoped_ptr<DiskMountManager::Disk> disk1(new DiskMountManager::Disk(
+ std::string(kTestDevicePath),
+ std::string(),
+ std::string(kTestSystemPath),
+ std::string(kTestFilePath),
+ std::string(),
+ std::string(kTestDriveLabel),
+ std::string(kTestUuid),
+ std::string(kTestSystemPathPrefix),
+ DEVICE_TYPE_USB,
+ 4294967295U,
+ false, // is_parent
+ false, // is_read_only
+ true, // has_media
+ false, // on_boot_device
+ false)); // is_hidden
+
+ disks_.clear();
+ disks_.insert(std::pair<std::string, DiskMountManager::Disk*>(
+ std::string(kTestDevicePath), disk1.get()));
+
+ // Device Added
+ DiskMountManagerEventType event;
+ event = MOUNT_DEVICE_ADDED;
+ NotifyDeviceChanged(event, kTestSystemPath);
+
+ // Disk Added
+ event = MOUNT_DISK_ADDED;
+ NotifyDiskChanged(event, disk1.get());
+
+ // Disk Changed
+ scoped_ptr<DiskMountManager::Disk> disk2(new DiskMountManager::Disk(
+ std::string(kTestDevicePath),
+ std::string(kTestMountPath),
+ std::string(kTestSystemPath),
+ std::string(kTestFilePath),
+ std::string(kTestDeviceLabel),
+ std::string(kTestDriveLabel),
+ std::string(kTestUuid),
+ std::string(kTestSystemPathPrefix),
+ DEVICE_TYPE_MOBILE,
+ 1073741824,
+ false, // is_parent
+ false, // is_read_only
+ true, // has_media
+ false, // on_boot_device
+ false)); // is_hidden
+ disks_.clear();
+ disks_.insert(std::pair<std::string, DiskMountManager::Disk*>(
+ std::string(kTestDevicePath), disk2.get()));
+ event = MOUNT_DISK_CHANGED;
+ NotifyDiskChanged(event, disk2.get());
+}
+
+void MockDiskMountManager::NotifyDeviceRemoveEvents() {
+ scoped_ptr<DiskMountManager::Disk> disk(new DiskMountManager::Disk(
+ std::string(kTestDevicePath),
+ std::string(kTestMountPath),
+ std::string(kTestSystemPath),
+ std::string(kTestFilePath),
+ std::string(kTestDeviceLabel),
+ std::string(kTestDriveLabel),
+ std::string(kTestUuid),
+ std::string(kTestSystemPathPrefix),
+ DEVICE_TYPE_SD,
+ 1073741824,
+ false, // is_parent
+ false, // is_read_only
+ true, // has_media
+ false, // on_boot_device
+ false)); // is_hidden
+ disks_.clear();
+ disks_.insert(std::pair<std::string, DiskMountManager::Disk*>(
+ std::string(kTestDevicePath), disk.get()));
+ NotifyDiskChanged(MOUNT_DISK_REMOVED, disk.get());
+}
+
+void MockDiskMountManager::SetupDefaultReplies() {
+ EXPECT_CALL(*this, AddObserver(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, RemoveObserver(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, disks())
+ .WillRepeatedly(ReturnRef(disks_));
+ EXPECT_CALL(*this, mount_points())
+ .WillRepeatedly(ReturnRef(mount_points_));
+ EXPECT_CALL(*this, FindDiskBySourcePath(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, RequestMountInfoRefresh())
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, MountPath(_, _, _, _))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, UnmountPath(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, FormatUnmountedDevice(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, FormatMountedDevice(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*this, UnmountDeviceRecursive(_, _, _))
+ .Times(AnyNumber());
+}
+
+void MockDiskMountManager::CreateDiskEntryForMountDevice(
+ const DiskMountManager::MountPointInfo& mount_info,
+ const std::string& device_id) {
+ Disk* disk = new DiskMountManager::Disk(std::string(mount_info.source_path),
+ std::string(mount_info.mount_path),
+ std::string(), // system_path
+ std::string(), // file_path
+ std::string(), // device_label
+ std::string(), // drive_label
+ device_id, // fs_uuid
+ std::string(), // system_path_prefix
+ DEVICE_TYPE_USB, // device_type
+ 1073741824, // total_size_in_bytes
+ false, // is_parent
+ false, // is_read_only
+ true, // has_media
+ false, // on_boot_device
+ false); // is_hidden
+ DiskMountManager::DiskMap::iterator it = disks_.find(mount_info.source_path);
+ if (it == disks_.end()) {
+ disks_.insert(std::make_pair(std::string(mount_info.source_path), disk));
+ } else {
+ delete it->second;
+ it->second = disk;
+ }
+}
+
+void MockDiskMountManager::RemoveDiskEntryForMountDevice(
+ const DiskMountManager::MountPointInfo& mount_info) {
+ DiskMountManager::DiskMap::iterator it = disks_.find(mount_info.source_path);
+ if (it != disks_.end()) {
+ delete it->second;
+ disks_.erase(it);
+ }
+}
+
+const DiskMountManager::MountPointMap&
+MockDiskMountManager::mountPointsInternal() const {
+ return mount_points_;
+}
+
+const DiskMountManager::Disk*
+MockDiskMountManager::FindDiskBySourcePathInternal(
+ const std::string& source_path) const {
+ DiskMap::const_iterator disk_it = disks_.find(source_path);
+ return disk_it == disks_.end() ? NULL : disk_it->second;
+}
+
+void MockDiskMountManager::NotifyDiskChanged(
+ DiskMountManagerEventType event,
+ const DiskMountManager::Disk* disk) {
+ FOR_EACH_OBSERVER(Observer, observers_, DiskChanged(event, disk));
+}
+
+void MockDiskMountManager::NotifyDeviceChanged(DiskMountManagerEventType event,
+ const std::string& path) {
+ FOR_EACH_OBSERVER(Observer, observers_, DeviceChanged(event, path));
+}
+
+} // namespace disks
+} // namespace chromeos
diff --git a/chromeos/disks/mock_disk_mount_manager.h b/chromeos/disks/mock_disk_mount_manager.h
new file mode 100644
index 0000000..169f33d
--- /dev/null
+++ b/chromeos/disks/mock_disk_mount_manager.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 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_MOCK_DISK_MOUNT_MANAGER_H_
+#define CHROMEOS_DISKS_MOCK_DISK_MOUNT_MANAGER_H_
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/time.h"
+#include "chromeos/disks/disk_mount_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace disks {
+
+class MockDiskMountManager : public DiskMountManager {
+ public:
+ MockDiskMountManager();
+ virtual ~MockDiskMountManager();
+
+ // DiskMountManager override.
+ MOCK_METHOD0(Init, void(void));
+ MOCK_METHOD1(AddObserver, void(DiskMountManager::Observer*));
+ MOCK_METHOD1(RemoveObserver, void(DiskMountManager::Observer*));
+ MOCK_CONST_METHOD0(disks, const DiskMountManager::DiskMap&(void));
+ MOCK_CONST_METHOD1(FindDiskBySourcePath,
+ const DiskMountManager::Disk*(const std::string&));
+ MOCK_CONST_METHOD0(mount_points,
+ const DiskMountManager::MountPointMap&(void));
+ MOCK_METHOD0(RequestMountInfoRefresh, void(void));
+ MOCK_METHOD4(MountPath, void(const std::string&, const std::string&,
+ const std::string&, MountType));
+ MOCK_METHOD1(UnmountPath, void(const std::string&));
+ MOCK_METHOD1(FormatUnmountedDevice, void(const std::string&));
+ MOCK_METHOD1(FormatMountedDevice, void(const std::string&));
+ MOCK_METHOD3(UnmountDeviceRecursive, void(const std::string&,
+ DiskMountManager::UnmountDeviceRecursiveCallbackType, void*));
+
+ // Invokes fake device insert events.
+ void NotifyDeviceInsertEvents();
+
+ // Invokes fake device remove events.
+ void NotifyDeviceRemoveEvents();
+
+ // Sets up default results for mock methods.
+ void SetupDefaultReplies();
+
+ // Creates a fake disk entry for the mounted device. This function is
+ // primarily for MediaDeviceNotificationsTest.
+ void CreateDiskEntryForMountDevice(
+ const DiskMountManager::MountPointInfo& mount_info,
+ const std::string& device_id);
+
+ // Removes the fake disk entry associated with the mounted device. This
+ // function is primarily for MediaDeviceNotificationsTest.
+ void RemoveDiskEntryForMountDevice(
+ const DiskMountManager::MountPointInfo& mount_info);
+
+ private:
+ // Is used to implement AddObserver.
+ void AddObserverInternal(DiskMountManager::Observer* observer);
+
+ // Is used to implement RemoveObserver.
+ void RemoveObserverInternal(DiskMountManager::Observer* observer);
+
+ // Is used to implement disks.
+ const DiskMountManager::DiskMap& disksInternal() const { return disks_; }
+
+ const DiskMountManager::MountPointMap& mountPointsInternal() const;
+
+ // Returns Disk object associated with the |source_path| or NULL on failure.
+ const DiskMountManager::Disk* FindDiskBySourcePathInternal(
+ const std::string& source_path) const;
+
+ // Notifies observers about device status update.
+ void NotifyDeviceChanged(DiskMountManagerEventType event,
+ const std::string& path);
+
+ // Notifies observers about disk status update.
+ void NotifyDiskChanged(DiskMountManagerEventType event,
+ const DiskMountManager::Disk* disk);
+
+ // The list of observers.
+ ObserverList<DiskMountManager::Observer> observers_;
+
+ // The list of disks found.
+ DiskMountManager::DiskMap disks_;
+
+ // The list of existing mount points.
+ DiskMountManager::MountPointMap mount_points_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDiskMountManager);
+};
+
+} // namespace disks
+} // namespace chromeos
+
+#endif // CHROMEOS_DISKS_MOCK_DISK_MOUNT_MANAGER_H_