blob: d4edfea38a9d54a2803c5bf35706907c7c9e5b0d [file] [log] [blame]
[email protected]2321d282012-01-31 23:06:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]4ae73292011-11-15 05:20:182// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4cbead42012-08-26 12:02:395#include "chromeos/disks/disk_mount_manager.h"
[email protected]a66a23cb2012-06-19 23:15:336
avi6e1a22d2015-12-21 03:43:207#include <stddef.h>
8#include <stdint.h>
9
[email protected]4ae73292011-11-15 05:20:1810#include <set>
11
[email protected]4ae73292011-11-15 05:20:1812#include "base/bind.h"
avi6e1a22d2015-12-21 03:43:2013#include "base/macros.h"
[email protected]c6944272012-01-06 22:12:2814#include "base/memory/weak_ptr.h"
[email protected]3fc40c142011-12-01 13:09:0415#include "base/observer_list.h"
[email protected]2bc706d2012-11-21 15:55:4716#include "base/stl_util.h"
[email protected]afa339d72013-06-11 06:32:5117#include "base/strings/string_util.h"
[email protected]64e199252012-04-06 01:54:3618#include "chromeos/dbus/dbus_thread_manager.h"
hirono9f5eae542015-06-22 04:28:4119#include "chromeos/disks/suspend_unmount_manager.h"
[email protected]4ae73292011-11-15 05:20:1820
21namespace chromeos {
22namespace disks {
23
24namespace {
25
26const char kDeviceNotFound[] = "Device could not be found";
27
28DiskMountManager* g_disk_mount_manager = NULL;
29
30// The DiskMountManager implementation.
31class DiskMountManagerImpl : public DiskMountManager {
32 public:
[email protected]a2e4ee22014-07-11 05:16:3533 DiskMountManagerImpl() :
34 already_refreshed_(false),
35 weak_ptr_factory_(this) {
[email protected]4ae73292011-11-15 05:20:1836 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get();
[email protected]4ae73292011-11-15 05:20:1837 cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient();
hirono9f5eae542015-06-22 04:28:4138 PowerManagerClient* power_manager_client =
39 dbus_thread_manager->GetPowerManagerClient();
40 suspend_unmount_manager_.reset(
41 new SuspendUnmountManager(this, power_manager_client));
[email protected]a0278d52014-05-06 03:36:1542 cros_disks_client_->SetMountEventHandler(
[email protected]4ae73292011-11-15 05:20:1843 base::Bind(&DiskMountManagerImpl::OnMountEvent,
[email protected]a0278d52014-05-06 03:36:1544 weak_ptr_factory_.GetWeakPtr()));
45 cros_disks_client_->SetMountCompletedHandler(
[email protected]4ae73292011-11-15 05:20:1846 base::Bind(&DiskMountManagerImpl::OnMountCompleted,
47 weak_ptr_factory_.GetWeakPtr()));
[email protected]a0278d52014-05-06 03:36:1548 cros_disks_client_->SetFormatCompletedHandler(
49 base::Bind(&DiskMountManagerImpl::OnFormatCompleted,
50 weak_ptr_factory_.GetWeakPtr()));
[email protected]4ae73292011-11-15 05:20:1851 }
52
dchengae98daa2015-01-21 20:30:4953 ~DiskMountManagerImpl() override {
[email protected]2bc706d2012-11-21 15:55:4754 STLDeleteContainerPairSecondPointers(disks_.begin(), disks_.end());
[email protected]4ae73292011-11-15 05:20:1855 }
56
57 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:4958 void AddObserver(Observer* observer) override {
[email protected]4ae73292011-11-15 05:20:1859 observers_.AddObserver(observer);
60 }
61
62 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:4963 void RemoveObserver(Observer* observer) override {
[email protected]4ae73292011-11-15 05:20:1864 observers_.RemoveObserver(observer);
65 }
66
67 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:4968 void MountPath(const std::string& source_path,
69 const std::string& source_format,
70 const std::string& mount_label,
71 MountType type) override {
[email protected]4ae73292011-11-15 05:20:1872 // Hidden and non-existent devices should not be mounted.
73 if (type == MOUNT_TYPE_DEVICE) {
74 DiskMap::const_iterator it = disks_.find(source_path);
75 if (it == disks_.end() || it->second->is_hidden()) {
[email protected]d7760592014-05-16 07:57:5276 OnMountCompleted(MountEntry(MOUNT_ERROR_INTERNAL, source_path, type,
77 ""));
[email protected]4ae73292011-11-15 05:20:1878 return;
79 }
80 }
[email protected]4ae73292011-11-15 05:20:1881 cros_disks_client_->Mount(
82 source_path,
[email protected]b9f22d12012-04-25 21:46:4883 source_format,
[email protected]dcad8fc2012-04-30 23:31:3384 mount_label,
[email protected]4ae73292011-11-15 05:20:1885 // When succeeds, OnMountCompleted will be called by
86 // "MountCompleted" signal instead.
[email protected]c6944272012-01-06 22:12:2887 base::Bind(&base::DoNothing),
[email protected]4ae73292011-11-15 05:20:1888 base::Bind(&DiskMountManagerImpl::OnMountCompleted,
89 weak_ptr_factory_.GetWeakPtr(),
[email protected]d7760592014-05-16 07:57:5290 MountEntry(MOUNT_ERROR_INTERNAL, source_path, type, "")));
[email protected]4ae73292011-11-15 05:20:1891 }
92
93 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:4994 void UnmountPath(const std::string& mount_path,
95 UnmountOptions options,
96 const UnmountPathCallback& callback) override {
[email protected]3af8e1b2012-09-15 20:46:0597 UnmountChildMounts(mount_path);
[email protected]10795ae2012-10-10 07:33:4998 cros_disks_client_->Unmount(mount_path, options,
[email protected]4ae73292011-11-15 05:20:1899 base::Bind(&DiskMountManagerImpl::OnUnmountPath,
[email protected]10795ae2012-10-10 07:33:49100 weak_ptr_factory_.GetWeakPtr(),
[email protected]8f919ee2013-03-14 19:53:29101 callback,
[email protected]ffdcc7a9c2013-07-02 06:59:39102 true,
103 mount_path),
[email protected]10795ae2012-10-10 07:33:49104 base::Bind(&DiskMountManagerImpl::OnUnmountPath,
105 weak_ptr_factory_.GetWeakPtr(),
[email protected]8f919ee2013-03-14 19:53:29106 callback,
[email protected]ffdcc7a9c2013-07-02 06:59:39107 false,
108 mount_path));
[email protected]4ae73292011-11-15 05:20:18109 }
110
111 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49112 void FormatMountedDevice(const std::string& mount_path) override {
[email protected]e3c1fc92012-11-15 00:56:46113 MountPointMap::const_iterator mount_point = mount_points_.find(mount_path);
114 if (mount_point == mount_points_.end()) {
115 LOG(ERROR) << "Mount point with path \"" << mount_path << "\" not found.";
[email protected]f026c0f2014-05-06 21:52:35116 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, mount_path);
[email protected]4ae73292011-11-15 05:20:18117 return;
118 }
[email protected]e3c1fc92012-11-15 00:56:46119
120 std::string device_path = mount_point->second.source_path;
121 DiskMap::const_iterator disk = disks_.find(device_path);
122 if (disk == disks_.end()) {
123 LOG(ERROR) << "Device with path \"" << device_path << "\" not found.";
[email protected]f026c0f2014-05-06 21:52:35124 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path);
[email protected]e3c1fc92012-11-15 00:56:46125 return;
126 }
127
[email protected]8f919ee2013-03-14 19:53:29128 UnmountPath(disk->second->mount_path(),
129 UNMOUNT_OPTIONS_NONE,
130 base::Bind(&DiskMountManagerImpl::OnUnmountPathForFormat,
131 weak_ptr_factory_.GetWeakPtr(),
132 device_path));
[email protected]4ae73292011-11-15 05:20:18133 }
134
135 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49136 void UnmountDeviceRecursively(
[email protected]4ae73292011-11-15 05:20:18137 const std::string& device_path,
mostynb4f4cf142014-10-06 13:57:52138 const UnmountDeviceRecursivelyCallbackType& callback) override {
[email protected]4ae73292011-11-15 05:20:18139 std::vector<std::string> devices_to_unmount;
140
141 // Get list of all devices to unmount.
142 int device_path_len = device_path.length();
143 for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) {
144 if (!it->second->mount_path().empty() &&
145 strncmp(device_path.c_str(), it->second->device_path().c_str(),
146 device_path_len) == 0) {
147 devices_to_unmount.push_back(it->second->mount_path());
148 }
149 }
[email protected]e008d4fa2013-02-21 06:38:01150
[email protected]4ae73292011-11-15 05:20:18151 // We should detect at least original device.
152 if (devices_to_unmount.empty()) {
153 if (disks_.find(device_path) == disks_.end()) {
[email protected]e008d4fa2013-02-21 06:38:01154 LOG(WARNING) << "Unmount recursive request failed for device "
155 << device_path << ", with error: " << kDeviceNotFound;
156 callback.Run(false);
[email protected]4ae73292011-11-15 05:20:18157 return;
158 }
[email protected]e008d4fa2013-02-21 06:38:01159
160 // Nothing to unmount.
161 callback.Run(true);
162 return;
[email protected]4ae73292011-11-15 05:20:18163 }
[email protected]e008d4fa2013-02-21 06:38:01164
165 // We will send the same callback data object to all Unmount calls and use
[email protected]a2e4ee22014-07-11 05:16:35166 // it to synchronize callbacks.
[email protected]e008d4fa2013-02-21 06:38:01167 // Note: this implementation has a potential memory leak issue. For
168 // example if this instance is destructed before all the callbacks for
169 // Unmount are invoked, the memory pointed by |cb_data| will be leaked.
170 // It is because the UnmountDeviceRecursivelyCallbackData keeps how
171 // many times OnUnmountDeviceRecursively callback is called and when
172 // all the callbacks are called, |cb_data| will be deleted in the method.
173 // However destructing the instance before all callback invocations will
174 // cancel all pending callbacks, so that the |cb_data| would never be
175 // deleted.
176 // Fortunately, in the real scenario, the instance will be destructed
177 // only for ShutDown. So, probably the memory would rarely be leaked.
178 // TODO(hidehiko): Fix the issue.
179 UnmountDeviceRecursivelyCallbackData* cb_data =
180 new UnmountDeviceRecursivelyCallbackData(
181 callback, devices_to_unmount.size());
182 for (size_t i = 0; i < devices_to_unmount.size(); ++i) {
183 cros_disks_client_->Unmount(
184 devices_to_unmount[i],
185 UNMOUNT_OPTIONS_NONE,
186 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively,
[email protected]ffdcc7a9c2013-07-02 06:59:39187 weak_ptr_factory_.GetWeakPtr(),
188 cb_data,
189 true,
190 devices_to_unmount[i]),
[email protected]e008d4fa2013-02-21 06:38:01191 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively,
[email protected]ffdcc7a9c2013-07-02 06:59:39192 weak_ptr_factory_.GetWeakPtr(),
193 cb_data,
194 false,
195 devices_to_unmount[i]));
[email protected]4ae73292011-11-15 05:20:18196 }
197 }
198
199 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49200 void EnsureMountInfoRefreshed(
hironoa4b675d2015-07-29 01:13:37201 const EnsureMountInfoRefreshedCallback& callback,
202 bool force) override {
203 if (!force && already_refreshed_) {
[email protected]a2e4ee22014-07-11 05:16:35204 callback.Run(true);
205 return;
206 }
207
208 refresh_callbacks_.push_back(callback);
209 if (refresh_callbacks_.size() == 1) {
210 // If there's no in-flight refreshing task, start it.
211 cros_disks_client_->EnumerateAutoMountableDevices(
212 base::Bind(&DiskMountManagerImpl::RefreshAfterEnumerateDevices,
213 weak_ptr_factory_.GetWeakPtr()),
214 base::Bind(&DiskMountManagerImpl::RefreshCompleted,
215 weak_ptr_factory_.GetWeakPtr(), false));
216 }
[email protected]4ae73292011-11-15 05:20:18217 }
218
219 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49220 const DiskMap& disks() const override { return disks_; }
[email protected]4ae73292011-11-15 05:20:18221
[email protected]bcfa0072012-08-07 01:08:57222 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49223 const Disk* FindDiskBySourcePath(
224 const std::string& source_path) const override {
[email protected]bcfa0072012-08-07 01:08:57225 DiskMap::const_iterator disk_it = disks_.find(source_path);
226 return disk_it == disks_.end() ? NULL : disk_it->second;
227 }
[email protected]4ae73292011-11-15 05:20:18228
229 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49230 const MountPointMap& mount_points() const override { return mount_points_; }
[email protected]4ae73292011-11-15 05:20:18231
[email protected]e3c1fc92012-11-15 00:56:46232 // DiskMountManager override.
dchengae98daa2015-01-21 20:30:49233 bool AddDiskForTest(Disk* disk) override {
[email protected]e3c1fc92012-11-15 00:56:46234 if (disks_.find(disk->device_path()) != disks_.end()) {
235 LOG(ERROR) << "Attempt to add a duplicate disk";
236 return false;
237 }
238
239 disks_.insert(std::make_pair(disk->device_path(), disk));
240 return true;
241 }
242
243 // DiskMountManager override.
244 // Corresponding disk should be added to the manager before this is called.
dchengae98daa2015-01-21 20:30:49245 bool AddMountPointForTest(const MountPointInfo& mount_point) override {
[email protected]e3c1fc92012-11-15 00:56:46246 if (mount_points_.find(mount_point.mount_path) != mount_points_.end()) {
247 LOG(ERROR) << "Attempt to add a duplicate mount point";
248 return false;
249 }
250 if (mount_point.mount_type == chromeos::MOUNT_TYPE_DEVICE &&
251 disks_.find(mount_point.source_path) == disks_.end()) {
252 LOG(ERROR) << "Device mount points must have a disk entry.";
253 return false;
254 }
255
256 mount_points_.insert(std::make_pair(mount_point.mount_path, mount_point));
257 return true;
258 }
259
[email protected]4ae73292011-11-15 05:20:18260 private:
[email protected]e008d4fa2013-02-21 06:38:01261 struct UnmountDeviceRecursivelyCallbackData {
262 UnmountDeviceRecursivelyCallbackData(
263 const UnmountDeviceRecursivelyCallbackType& in_callback,
264 int in_num_pending_callbacks)
265 : callback(in_callback),
266 num_pending_callbacks(in_num_pending_callbacks) {
[email protected]4ae73292011-11-15 05:20:18267 }
[email protected]e008d4fa2013-02-21 06:38:01268
269 const UnmountDeviceRecursivelyCallbackType callback;
270 size_t num_pending_callbacks;
[email protected]4ae73292011-11-15 05:20:18271 };
272
[email protected]3af8e1b2012-09-15 20:46:05273 // Unmounts all mount points whose source path is transitively parented by
274 // |mount_path|.
275 void UnmountChildMounts(const std::string& mount_path_in) {
276 std::string mount_path = mount_path_in;
277 // Let's make sure mount path has trailing slash.
pkasting9022cb42016-02-05 00:08:56278 if (mount_path.back() != '/')
[email protected]3af8e1b2012-09-15 20:46:05279 mount_path += '/';
280
281 for (MountPointMap::iterator it = mount_points_.begin();
282 it != mount_points_.end();
283 ++it) {
brettw95509312015-07-16 23:57:33284 if (base::StartsWith(it->second.source_path, mount_path,
285 base::CompareCase::SENSITIVE)) {
[email protected]8f919ee2013-03-14 19:53:29286 // TODO(tbarzic): Handle the case where this fails.
287 UnmountPath(it->second.mount_path,
288 UNMOUNT_OPTIONS_NONE,
289 UnmountPathCallback());
[email protected]3af8e1b2012-09-15 20:46:05290 }
291 }
292 }
293
[email protected]e008d4fa2013-02-21 06:38:01294 // Callback for UnmountDeviceRecursively.
295 void OnUnmountDeviceRecursively(
296 UnmountDeviceRecursivelyCallbackData* cb_data,
297 bool success,
298 const std::string& mount_path) {
[email protected]4ae73292011-11-15 05:20:18299 if (success) {
300 // Do standard processing for Unmount event.
[email protected]8f919ee2013-03-14 19:53:29301 OnUnmountPath(UnmountPathCallback(), true, mount_path);
[email protected]a0278d52014-05-06 03:36:15302 VLOG(1) << mount_path << " unmounted.";
[email protected]4ae73292011-11-15 05:20:18303 }
304 // This is safe as long as all callbacks are called on the same thread as
[email protected]e008d4fa2013-02-21 06:38:01305 // UnmountDeviceRecursively.
306 cb_data->num_pending_callbacks--;
[email protected]4ae73292011-11-15 05:20:18307
[email protected]e008d4fa2013-02-21 06:38:01308 if (cb_data->num_pending_callbacks == 0) {
309 // This code has a problem that the |success| status used here is for the
310 // last "unmount" callback, but not whether all unmounting is succeeded.
311 // TODO(hidehiko): Fix the issue.
312 cb_data->callback.Run(success);
[email protected]4ae73292011-11-15 05:20:18313 delete cb_data;
314 }
315 }
316
317 // Callback to handle MountCompleted signal and Mount method call failure.
[email protected]d7760592014-05-16 07:57:52318 void OnMountCompleted(const MountEntry& entry) {
[email protected]4ae73292011-11-15 05:20:18319 MountCondition mount_condition = MOUNT_CONDITION_NONE;
[email protected]d7760592014-05-16 07:57:52320 if (entry.mount_type() == MOUNT_TYPE_DEVICE) {
321 if (entry.error_code() == MOUNT_ERROR_UNKNOWN_FILESYSTEM) {
[email protected]4ae73292011-11-15 05:20:18322 mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM;
[email protected]a66a23cb2012-06-19 23:15:33323 }
[email protected]d7760592014-05-16 07:57:52324 if (entry.error_code() == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM) {
[email protected]4ae73292011-11-15 05:20:18325 mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM;
[email protected]a66a23cb2012-06-19 23:15:33326 }
[email protected]4ae73292011-11-15 05:20:18327 }
[email protected]d7760592014-05-16 07:57:52328 const MountPointInfo mount_info(entry.source_path(),
329 entry.mount_path(),
330 entry.mount_type(),
[email protected]4ae73292011-11-15 05:20:18331 mount_condition);
332
[email protected]d7760592014-05-16 07:57:52333 NotifyMountStatusUpdate(MOUNTING, entry.error_code(), mount_info);
[email protected]4ae73292011-11-15 05:20:18334
335 // If the device is corrupted but it's still possible to format it, it will
336 // be fake mounted.
[email protected]d7760592014-05-16 07:57:52337 if ((entry.error_code() == MOUNT_ERROR_NONE ||
338 mount_info.mount_condition) &&
[email protected]4ae73292011-11-15 05:20:18339 mount_points_.find(mount_info.mount_path) == mount_points_.end()) {
340 mount_points_.insert(MountPointMap::value_type(mount_info.mount_path,
341 mount_info));
342 }
[email protected]d7760592014-05-16 07:57:52343 if ((entry.error_code() == MOUNT_ERROR_NONE ||
344 mount_info.mount_condition) &&
[email protected]4ae73292011-11-15 05:20:18345 mount_info.mount_type == MOUNT_TYPE_DEVICE &&
346 !mount_info.source_path.empty() &&
347 !mount_info.mount_path.empty()) {
348 DiskMap::iterator iter = disks_.find(mount_info.source_path);
349 if (iter == disks_.end()) {
350 // disk might have been removed by now?
351 return;
352 }
353 Disk* disk = iter->second;
354 DCHECK(disk);
355 disk->set_mount_path(mount_info.mount_path);
[email protected]4ae73292011-11-15 05:20:18356 }
357 }
358
359 // Callback for UnmountPath.
[email protected]8f919ee2013-03-14 19:53:29360 void OnUnmountPath(const UnmountPathCallback& callback,
361 bool success,
362 const std::string& mount_path) {
[email protected]4ae73292011-11-15 05:20:18363 MountPointMap::iterator mount_points_it = mount_points_.find(mount_path);
[email protected]8f919ee2013-03-14 19:53:29364 if (mount_points_it == mount_points_.end()) {
365 // The path was unmounted, but not as a result of this unmount request,
366 // so return error.
367 if (!callback.is_null())
368 callback.Run(MOUNT_ERROR_INTERNAL);
[email protected]4ae73292011-11-15 05:20:18369 return;
[email protected]8f919ee2013-03-14 19:53:29370 }
[email protected]e3c1fc92012-11-15 00:56:46371
372 NotifyMountStatusUpdate(
[email protected]10795ae2012-10-10 07:33:49373 UNMOUNTING,
374 success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL,
[email protected]a66a23cb2012-06-19 23:15:33375 MountPointInfo(mount_points_it->second.source_path,
376 mount_points_it->second.mount_path,
377 mount_points_it->second.mount_type,
378 mount_points_it->second.mount_condition));
[email protected]10795ae2012-10-10 07:33:49379
[email protected]4ae73292011-11-15 05:20:18380 std::string path(mount_points_it->second.source_path);
[email protected]10795ae2012-10-10 07:33:49381 if (success)
382 mount_points_.erase(mount_points_it);
383
[email protected]e3c1fc92012-11-15 00:56:46384 DiskMap::iterator disk_iter = disks_.find(path);
385 if (disk_iter != disks_.end()) {
386 DCHECK(disk_iter->second);
387 if (success)
388 disk_iter->second->clear_mount_path();
[email protected]4ae73292011-11-15 05:20:18389 }
[email protected]10795ae2012-10-10 07:33:49390
[email protected]8f919ee2013-03-14 19:53:29391 if (!callback.is_null())
392 callback.Run(success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL);
393 }
394
395 void OnUnmountPathForFormat(const std::string& device_path,
396 MountError error_code) {
397 if (error_code == MOUNT_ERROR_NONE &&
398 disks_.find(device_path) != disks_.end()) {
399 FormatUnmountedDevice(device_path);
400 } else {
[email protected]f026c0f2014-05-06 21:52:35401 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path);
[email protected]4ae73292011-11-15 05:20:18402 }
403 }
404
[email protected]e3c1fc92012-11-15 00:56:46405 // Starts device formatting.
406 void FormatUnmountedDevice(const std::string& device_path) {
407 DiskMap::const_iterator disk = disks_.find(device_path);
408 DCHECK(disk != disks_.end() && disk->second->mount_path().empty());
409
410 const char kFormatVFAT[] = "vfat";
[email protected]f026c0f2014-05-06 21:52:35411 cros_disks_client_->Format(
[email protected]e3c1fc92012-11-15 00:56:46412 device_path,
413 kFormatVFAT,
[email protected]f026c0f2014-05-06 21:52:35414 base::Bind(&DiskMountManagerImpl::OnFormatStarted,
[email protected]15a2c282013-07-03 08:39:49415 weak_ptr_factory_.GetWeakPtr(),
416 device_path),
[email protected]f026c0f2014-05-06 21:52:35417 base::Bind(&DiskMountManagerImpl::OnFormatCompleted,
[email protected]e3c1fc92012-11-15 00:56:46418 weak_ptr_factory_.GetWeakPtr(),
[email protected]f026c0f2014-05-06 21:52:35419 FORMAT_ERROR_UNKNOWN,
420 device_path));
[email protected]e3c1fc92012-11-15 00:56:46421 }
422
[email protected]f026c0f2014-05-06 21:52:35423 // Callback for Format.
424 void OnFormatStarted(const std::string& device_path) {
425 NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path);
[email protected]4ae73292011-11-15 05:20:18426 }
427
[email protected]a0278d52014-05-06 03:36:15428 // Callback to handle FormatCompleted signal and Format method call failure.
429 void OnFormatCompleted(FormatError error_code,
[email protected]f026c0f2014-05-06 21:52:35430 const std::string& device_path) {
431 NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path);
[email protected]a0278d52014-05-06 03:36:15432 }
433
[email protected]a2e4ee22014-07-11 05:16:35434 // Callback for GetDeviceProperties.
[email protected]4ae73292011-11-15 05:20:18435 void OnGetDeviceProperties(const DiskInfo& disk_info) {
436 // TODO(zelidrag): Find a better way to filter these out before we
437 // fetch the properties:
438 // Ignore disks coming from the device we booted the system from.
439 if (disk_info.on_boot_device())
440 return;
441
442 LOG(WARNING) << "Found disk " << disk_info.device_path();
443 // Delete previous disk info for this path:
444 bool is_new = true;
445 DiskMap::iterator iter = disks_.find(disk_info.device_path());
446 if (iter != disks_.end()) {
447 delete iter->second;
448 disks_.erase(iter);
449 is_new = false;
450 }
451 Disk* disk = new Disk(disk_info.device_path(),
452 disk_info.mount_path(),
453 disk_info.system_path(),
454 disk_info.file_path(),
455 disk_info.label(),
456 disk_info.drive_label(),
[email protected]202e9fee2012-09-13 20:21:29457 disk_info.vendor_id(),
458 disk_info.vendor_name(),
459 disk_info.product_id(),
460 disk_info.product_name(),
[email protected]9c5620d32012-07-31 01:00:38461 disk_info.uuid(),
[email protected]4ae73292011-11-15 05:20:18462 FindSystemPathPrefix(disk_info.system_path()),
463 disk_info.device_type(),
464 disk_info.total_size_in_bytes(),
465 disk_info.is_drive(),
466 disk_info.is_read_only(),
467 disk_info.has_media(),
468 disk_info.on_boot_device(),
[email protected]79ed457b2014-07-22 04:07:26469 disk_info.on_removable_device(),
[email protected]4ae73292011-11-15 05:20:18470 disk_info.is_hidden());
471 disks_.insert(std::make_pair(disk_info.device_path(), disk));
[email protected]e3c1fc92012-11-15 00:56:46472 NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, disk);
[email protected]4ae73292011-11-15 05:20:18473 }
474
[email protected]a2e4ee22014-07-11 05:16:35475 // Part of EnsureMountInfoRefreshed(). Called after the list of devices are
476 // enumerated.
477 void RefreshAfterEnumerateDevices(const std::vector<std::string>& devices) {
478 std::set<std::string> current_device_set(devices.begin(), devices.end());
[email protected]4ae73292011-11-15 05:20:18479 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) {
480 if (current_device_set.find(iter->first) == current_device_set.end()) {
[email protected]4ae73292011-11-15 05:20:18481 delete iter->second;
482 disks_.erase(iter++);
483 } else {
484 ++iter;
485 }
486 }
[email protected]a2e4ee22014-07-11 05:16:35487 RefreshDeviceAtIndex(devices, 0);
488 }
489
490 // Part of EnsureMountInfoRefreshed(). Called for each device to refresh info.
491 void RefreshDeviceAtIndex(const std::vector<std::string>& devices,
492 size_t index) {
493 if (index == devices.size()) {
494 // All devices info retrieved. Proceed to enumerate mount point info.
495 cros_disks_client_->EnumerateMountEntries(
496 base::Bind(&DiskMountManagerImpl::RefreshAfterEnumerateMountEntries,
497 weak_ptr_factory_.GetWeakPtr()),
498 base::Bind(&DiskMountManagerImpl::RefreshCompleted,
499 weak_ptr_factory_.GetWeakPtr(), false));
500 return;
501 }
502
503 cros_disks_client_->GetDeviceProperties(
504 devices[index],
505 base::Bind(&DiskMountManagerImpl::RefreshAfterGetDeviceProperties,
506 weak_ptr_factory_.GetWeakPtr(), devices, index + 1),
hirono8067bf02015-08-10 03:12:25507 base::Bind(&DiskMountManagerImpl::RefreshDeviceAtIndex,
508 weak_ptr_factory_.GetWeakPtr(), devices, index + 1));
[email protected]a2e4ee22014-07-11 05:16:35509 }
510
511 // Part of EnsureMountInfoRefreshed().
512 void RefreshAfterGetDeviceProperties(const std::vector<std::string>& devices,
513 size_t next_index,
514 const DiskInfo& disk_info) {
515 OnGetDeviceProperties(disk_info);
516 RefreshDeviceAtIndex(devices, next_index);
517 }
518
519 // Part of EnsureMountInfoRefreshed(). Called after mount entries are listed.
520 void RefreshAfterEnumerateMountEntries(
521 const std::vector<MountEntry>& entries) {
522 for (size_t i = 0; i < entries.size(); ++i)
523 OnMountCompleted(entries[i]);
524 RefreshCompleted(true);
525 }
526
527 // Part of EnsureMountInfoRefreshed(). Called when the refreshing is done.
528 void RefreshCompleted(bool success) {
529 already_refreshed_ = true;
530 for (size_t i = 0; i < refresh_callbacks_.size(); ++i)
531 refresh_callbacks_[i].Run(success);
532 refresh_callbacks_.clear();
[email protected]4ae73292011-11-15 05:20:18533 }
534
535 // Callback to handle mount event signals.
[email protected]e24f8762011-12-20 00:10:04536 void OnMountEvent(MountEventType event, const std::string& device_path_arg) {
537 // Take a copy of the argument so we can modify it below.
538 std::string device_path = device_path_arg;
[email protected]4ae73292011-11-15 05:20:18539 switch (event) {
[email protected]e3c1fc92012-11-15 00:56:46540 case CROS_DISKS_DISK_ADDED: {
[email protected]4ae73292011-11-15 05:20:18541 cros_disks_client_->GetDeviceProperties(
542 device_path,
543 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties,
544 weak_ptr_factory_.GetWeakPtr()),
[email protected]c6944272012-01-06 22:12:28545 base::Bind(&base::DoNothing));
[email protected]e3c1fc92012-11-15 00:56:46546 break;
[email protected]4ae73292011-11-15 05:20:18547 }
[email protected]e3c1fc92012-11-15 00:56:46548 case CROS_DISKS_DISK_REMOVED: {
[email protected]4ae73292011-11-15 05:20:18549 // Search and remove disks that are no longer present.
550 DiskMountManager::DiskMap::iterator iter = disks_.find(device_path);
551 if (iter != disks_.end()) {
552 Disk* disk = iter->second;
[email protected]e3c1fc92012-11-15 00:56:46553 NotifyDiskStatusUpdate(DISK_REMOVED, disk);
[email protected]4ae73292011-11-15 05:20:18554 delete iter->second;
555 disks_.erase(iter);
556 }
[email protected]e3c1fc92012-11-15 00:56:46557 break;
[email protected]4ae73292011-11-15 05:20:18558 }
[email protected]e3c1fc92012-11-15 00:56:46559 case CROS_DISKS_DEVICE_ADDED: {
[email protected]4ae73292011-11-15 05:20:18560 system_path_prefixes_.insert(device_path);
[email protected]e3c1fc92012-11-15 00:56:46561 NotifyDeviceStatusUpdate(DEVICE_ADDED, device_path);
[email protected]4ae73292011-11-15 05:20:18562 break;
563 }
[email protected]e3c1fc92012-11-15 00:56:46564 case CROS_DISKS_DEVICE_REMOVED: {
[email protected]4ae73292011-11-15 05:20:18565 system_path_prefixes_.erase(device_path);
[email protected]e3c1fc92012-11-15 00:56:46566 NotifyDeviceStatusUpdate(DEVICE_REMOVED, device_path);
[email protected]4ae73292011-11-15 05:20:18567 break;
568 }
[email protected]e3c1fc92012-11-15 00:56:46569 case CROS_DISKS_DEVICE_SCANNED: {
570 NotifyDeviceStatusUpdate(DEVICE_SCANNED, device_path);
[email protected]4ae73292011-11-15 05:20:18571 break;
572 }
[email protected]4ae73292011-11-15 05:20:18573 default: {
574 LOG(ERROR) << "Unknown event: " << event;
[email protected]4ae73292011-11-15 05:20:18575 }
576 }
[email protected]4ae73292011-11-15 05:20:18577 }
578
579 // Notifies all observers about disk status update.
[email protected]e3c1fc92012-11-15 00:56:46580 void NotifyDiskStatusUpdate(DiskEvent event,
[email protected]4ae73292011-11-15 05:20:18581 const Disk* disk) {
[email protected]e3c1fc92012-11-15 00:56:46582 FOR_EACH_OBSERVER(Observer, observers_, OnDiskEvent(event, disk));
[email protected]4ae73292011-11-15 05:20:18583 }
584
585 // Notifies all observers about device status update.
[email protected]e3c1fc92012-11-15 00:56:46586 void NotifyDeviceStatusUpdate(DeviceEvent event,
[email protected]4ae73292011-11-15 05:20:18587 const std::string& device_path) {
[email protected]e3c1fc92012-11-15 00:56:46588 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceEvent(event, device_path));
[email protected]4ae73292011-11-15 05:20:18589 }
590
591 // Notifies all observers about mount completion.
[email protected]e3c1fc92012-11-15 00:56:46592 void NotifyMountStatusUpdate(MountEvent event,
593 MountError error_code,
594 const MountPointInfo& mount_info) {
[email protected]4ae73292011-11-15 05:20:18595 FOR_EACH_OBSERVER(Observer, observers_,
[email protected]e3c1fc92012-11-15 00:56:46596 OnMountEvent(event, error_code, mount_info));
597 }
598
599 void NotifyFormatStatusUpdate(FormatEvent event,
600 FormatError error_code,
601 const std::string& device_path) {
602 FOR_EACH_OBSERVER(Observer, observers_,
603 OnFormatEvent(event, error_code, device_path));
[email protected]4ae73292011-11-15 05:20:18604 }
605
[email protected]4ae73292011-11-15 05:20:18606 // Finds system path prefix from |system_path|.
607 const std::string& FindSystemPathPrefix(const std::string& system_path) {
608 if (system_path.empty())
[email protected]8790210c2013-12-02 05:29:53609 return base::EmptyString();
[email protected]4ae73292011-11-15 05:20:18610 for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin();
611 it != system_path_prefixes_.end();
612 ++it) {
613 const std::string& prefix = *it;
brettw95509312015-07-16 23:57:33614 if (base::StartsWith(system_path, prefix, base::CompareCase::SENSITIVE))
[email protected]4ae73292011-11-15 05:20:18615 return prefix;
616 }
[email protected]8790210c2013-12-02 05:29:53617 return base::EmptyString();
[email protected]4ae73292011-11-15 05:20:18618 }
619
[email protected]4ae73292011-11-15 05:20:18620 // Mount event change observers.
brettw236d3172015-06-03 16:31:43621 base::ObserverList<Observer> observers_;
[email protected]4ae73292011-11-15 05:20:18622
623 CrosDisksClient* cros_disks_client_;
624
625 // The list of disks found.
626 DiskMountManager::DiskMap disks_;
627
628 DiskMountManager::MountPointMap mount_points_;
629
630 typedef std::set<std::string> SystemPathPrefixSet;
631 SystemPathPrefixSet system_path_prefixes_;
632
[email protected]a2e4ee22014-07-11 05:16:35633 bool already_refreshed_;
634 std::vector<EnsureMountInfoRefreshedCallback> refresh_callbacks_;
635
hirono9f5eae542015-06-22 04:28:41636 scoped_ptr<SuspendUnmountManager> suspend_unmount_manager_;
637
[email protected]4ae73292011-11-15 05:20:18638 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_;
639
640 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl);
641};
642
[email protected]a66a23cb2012-06-19 23:15:33643} // namespace
[email protected]4ae73292011-11-15 05:20:18644
645DiskMountManager::Disk::Disk(const std::string& device_path,
646 const std::string& mount_path,
647 const std::string& system_path,
648 const std::string& file_path,
649 const std::string& device_label,
650 const std::string& drive_label,
[email protected]202e9fee2012-09-13 20:21:29651 const std::string& vendor_id,
652 const std::string& vendor_name,
653 const std::string& product_id,
654 const std::string& product_name,
[email protected]9c5620d32012-07-31 01:00:38655 const std::string& fs_uuid,
[email protected]4ae73292011-11-15 05:20:18656 const std::string& system_path_prefix,
657 DeviceType device_type,
avi6e1a22d2015-12-21 03:43:20658 uint64_t total_size_in_bytes,
[email protected]4ae73292011-11-15 05:20:18659 bool is_parent,
660 bool is_read_only,
661 bool has_media,
662 bool on_boot_device,
[email protected]79ed457b2014-07-22 04:07:26663 bool on_removable_device,
[email protected]4ae73292011-11-15 05:20:18664 bool is_hidden)
665 : device_path_(device_path),
666 mount_path_(mount_path),
667 system_path_(system_path),
668 file_path_(file_path),
669 device_label_(device_label),
670 drive_label_(drive_label),
[email protected]202e9fee2012-09-13 20:21:29671 vendor_id_(vendor_id),
672 vendor_name_(vendor_name),
673 product_id_(product_id),
674 product_name_(product_name),
[email protected]9c5620d32012-07-31 01:00:38675 fs_uuid_(fs_uuid),
[email protected]4ae73292011-11-15 05:20:18676 system_path_prefix_(system_path_prefix),
677 device_type_(device_type),
678 total_size_in_bytes_(total_size_in_bytes),
679 is_parent_(is_parent),
680 is_read_only_(is_read_only),
681 has_media_(has_media),
682 on_boot_device_(on_boot_device),
[email protected]79ed457b2014-07-22 04:07:26683 on_removable_device_(on_removable_device),
avi6e1a22d2015-12-21 03:43:20684 is_hidden_(is_hidden) {}
[email protected]4ae73292011-11-15 05:20:18685
686DiskMountManager::Disk::~Disk() {}
687
[email protected]e3c1fc92012-11-15 00:56:46688bool DiskMountManager::AddDiskForTest(Disk* disk) {
689 return false;
690}
691
692bool DiskMountManager::AddMountPointForTest(const MountPointInfo& mount_point) {
693 return false;
694}
695
[email protected]4ae73292011-11-15 05:20:18696// static
[email protected]4ae73292011-11-15 05:20:18697std::string DiskMountManager::MountConditionToString(MountCondition condition) {
698 switch (condition) {
699 case MOUNT_CONDITION_NONE:
700 return "";
701 case MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
702 return "unknown_filesystem";
703 case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
704 return "unsupported_filesystem";
705 default:
706 NOTREACHED();
707 }
708 return "";
709}
710
711// static
[email protected]2321d282012-01-31 23:06:59712std::string DiskMountManager::DeviceTypeToString(DeviceType type) {
713 switch (type) {
714 case DEVICE_TYPE_USB:
715 return "usb";
716 case DEVICE_TYPE_SD:
717 return "sd";
718 case DEVICE_TYPE_OPTICAL_DISC:
719 return "optical";
720 case DEVICE_TYPE_MOBILE:
721 return "mobile";
722 default:
723 return "unknown";
724 }
725}
726
727// static
[email protected]4ae73292011-11-15 05:20:18728void DiskMountManager::Initialize() {
[email protected]b307bceb2011-11-17 07:49:55729 if (g_disk_mount_manager) {
730 LOG(WARNING) << "DiskMountManager was already initialized";
731 return;
732 }
[email protected]4ae73292011-11-15 05:20:18733 g_disk_mount_manager = new DiskMountManagerImpl();
[email protected]b307bceb2011-11-17 07:49:55734 VLOG(1) << "DiskMountManager initialized";
735}
736
737// static
738void DiskMountManager::InitializeForTesting(
739 DiskMountManager* disk_mount_manager) {
740 if (g_disk_mount_manager) {
741 LOG(WARNING) << "DiskMountManager was already initialized";
742 return;
743 }
744 g_disk_mount_manager = disk_mount_manager;
745 VLOG(1) << "DiskMountManager initialized";
[email protected]4ae73292011-11-15 05:20:18746}
747
748// static
749void DiskMountManager::Shutdown() {
[email protected]b307bceb2011-11-17 07:49:55750 if (!g_disk_mount_manager) {
751 LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager";
752 return;
[email protected]4ae73292011-11-15 05:20:18753 }
[email protected]b307bceb2011-11-17 07:49:55754 delete g_disk_mount_manager;
755 g_disk_mount_manager = NULL;
756 VLOG(1) << "DiskMountManager Shutdown completed";
[email protected]4ae73292011-11-15 05:20:18757}
758
759// static
760DiskMountManager* DiskMountManager::GetInstance() {
761 return g_disk_mount_manager;
762}
763
764} // namespace disks
765} // namespace chromeos