disk_mount_manager.cc revision 010d83a9304c5a91596085d917d248abff47903a
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chromeos/disks/disk_mount_manager.h" 6 7#include <map> 8#include <set> 9 10#include "base/bind.h" 11#include "base/memory/weak_ptr.h" 12#include "base/observer_list.h" 13#include "base/stl_util.h" 14#include "base/strings/string_util.h" 15#include "chromeos/dbus/dbus_thread_manager.h" 16 17namespace chromeos { 18namespace disks { 19 20namespace { 21 22const char kDeviceNotFound[] = "Device could not be found"; 23 24DiskMountManager* g_disk_mount_manager = NULL; 25 26// The DiskMountManager implementation. 27class DiskMountManagerImpl : public DiskMountManager { 28 public: 29 DiskMountManagerImpl() : weak_ptr_factory_(this) { 30 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); 31 DCHECK(dbus_thread_manager); 32 cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient(); 33 DCHECK(cros_disks_client_); 34 cros_disks_client_->SetMountEventHandler( 35 base::Bind(&DiskMountManagerImpl::OnMountEvent, 36 weak_ptr_factory_.GetWeakPtr())); 37 cros_disks_client_->SetMountCompletedHandler( 38 base::Bind(&DiskMountManagerImpl::OnMountCompleted, 39 weak_ptr_factory_.GetWeakPtr())); 40 cros_disks_client_->SetFormatCompletedHandler( 41 base::Bind(&DiskMountManagerImpl::OnFormatCompleted, 42 weak_ptr_factory_.GetWeakPtr())); 43 } 44 45 virtual ~DiskMountManagerImpl() { 46 STLDeleteContainerPairSecondPointers(disks_.begin(), disks_.end()); 47 } 48 49 // DiskMountManager override. 50 virtual void AddObserver(Observer* observer) OVERRIDE { 51 observers_.AddObserver(observer); 52 } 53 54 // DiskMountManager override. 55 virtual void RemoveObserver(Observer* observer) OVERRIDE { 56 observers_.RemoveObserver(observer); 57 } 58 59 // DiskMountManager override. 60 virtual void MountPath(const std::string& source_path, 61 const std::string& source_format, 62 const std::string& mount_label, 63 MountType type) OVERRIDE { 64 // Hidden and non-existent devices should not be mounted. 65 if (type == MOUNT_TYPE_DEVICE) { 66 DiskMap::const_iterator it = disks_.find(source_path); 67 if (it == disks_.end() || it->second->is_hidden()) { 68 OnMountCompleted(MOUNT_ERROR_INTERNAL, source_path, type, ""); 69 return; 70 } 71 } 72 cros_disks_client_->Mount( 73 source_path, 74 source_format, 75 mount_label, 76 // When succeeds, OnMountCompleted will be called by 77 // "MountCompleted" signal instead. 78 base::Bind(&base::DoNothing), 79 base::Bind(&DiskMountManagerImpl::OnMountCompleted, 80 weak_ptr_factory_.GetWeakPtr(), 81 MOUNT_ERROR_INTERNAL, 82 source_path, 83 type, 84 "")); 85 } 86 87 // DiskMountManager override. 88 virtual void UnmountPath(const std::string& mount_path, 89 UnmountOptions options, 90 const UnmountPathCallback& callback) OVERRIDE { 91 UnmountChildMounts(mount_path); 92 cros_disks_client_->Unmount(mount_path, options, 93 base::Bind(&DiskMountManagerImpl::OnUnmountPath, 94 weak_ptr_factory_.GetWeakPtr(), 95 callback, 96 true, 97 mount_path), 98 base::Bind(&DiskMountManagerImpl::OnUnmountPath, 99 weak_ptr_factory_.GetWeakPtr(), 100 callback, 101 false, 102 mount_path)); 103 } 104 105 // DiskMountManager override. 106 virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE { 107 MountPointMap::const_iterator mount_point = mount_points_.find(mount_path); 108 if (mount_point == mount_points_.end()) { 109 LOG(ERROR) << "Mount point with path \"" << mount_path << "\" not found."; 110 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, mount_path); 111 return; 112 } 113 114 std::string device_path = mount_point->second.source_path; 115 DiskMap::const_iterator disk = disks_.find(device_path); 116 if (disk == disks_.end()) { 117 LOG(ERROR) << "Device with path \"" << device_path << "\" not found."; 118 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path); 119 return; 120 } 121 122 UnmountPath(disk->second->mount_path(), 123 UNMOUNT_OPTIONS_NONE, 124 base::Bind(&DiskMountManagerImpl::OnUnmountPathForFormat, 125 weak_ptr_factory_.GetWeakPtr(), 126 device_path)); 127 } 128 129 // DiskMountManager override. 130 virtual void UnmountDeviceRecursively( 131 const std::string& device_path, 132 const UnmountDeviceRecursivelyCallbackType& callback) OVERRIDE { 133 std::vector<std::string> devices_to_unmount; 134 135 // Get list of all devices to unmount. 136 int device_path_len = device_path.length(); 137 for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) { 138 if (!it->second->mount_path().empty() && 139 strncmp(device_path.c_str(), it->second->device_path().c_str(), 140 device_path_len) == 0) { 141 devices_to_unmount.push_back(it->second->mount_path()); 142 } 143 } 144 145 // We should detect at least original device. 146 if (devices_to_unmount.empty()) { 147 if (disks_.find(device_path) == disks_.end()) { 148 LOG(WARNING) << "Unmount recursive request failed for device " 149 << device_path << ", with error: " << kDeviceNotFound; 150 callback.Run(false); 151 return; 152 } 153 154 // Nothing to unmount. 155 callback.Run(true); 156 return; 157 } 158 159 // We will send the same callback data object to all Unmount calls and use 160 // it to syncronize callbacks. 161 // Note: this implementation has a potential memory leak issue. For 162 // example if this instance is destructed before all the callbacks for 163 // Unmount are invoked, the memory pointed by |cb_data| will be leaked. 164 // It is because the UnmountDeviceRecursivelyCallbackData keeps how 165 // many times OnUnmountDeviceRecursively callback is called and when 166 // all the callbacks are called, |cb_data| will be deleted in the method. 167 // However destructing the instance before all callback invocations will 168 // cancel all pending callbacks, so that the |cb_data| would never be 169 // deleted. 170 // Fortunately, in the real scenario, the instance will be destructed 171 // only for ShutDown. So, probably the memory would rarely be leaked. 172 // TODO(hidehiko): Fix the issue. 173 UnmountDeviceRecursivelyCallbackData* cb_data = 174 new UnmountDeviceRecursivelyCallbackData( 175 callback, devices_to_unmount.size()); 176 for (size_t i = 0; i < devices_to_unmount.size(); ++i) { 177 cros_disks_client_->Unmount( 178 devices_to_unmount[i], 179 UNMOUNT_OPTIONS_NONE, 180 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively, 181 weak_ptr_factory_.GetWeakPtr(), 182 cb_data, 183 true, 184 devices_to_unmount[i]), 185 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively, 186 weak_ptr_factory_.GetWeakPtr(), 187 cb_data, 188 false, 189 devices_to_unmount[i])); 190 } 191 } 192 193 // DiskMountManager override. 194 virtual void RequestMountInfoRefresh() OVERRIDE { 195 cros_disks_client_->EnumerateAutoMountableDevices( 196 base::Bind(&DiskMountManagerImpl::OnRequestMountInfo, 197 weak_ptr_factory_.GetWeakPtr()), 198 base::Bind(&base::DoNothing)); 199 } 200 201 // DiskMountManager override. 202 virtual const DiskMap& disks() const OVERRIDE { return disks_; } 203 204 // DiskMountManager override. 205 virtual const Disk* FindDiskBySourcePath(const std::string& source_path) 206 const OVERRIDE { 207 DiskMap::const_iterator disk_it = disks_.find(source_path); 208 return disk_it == disks_.end() ? NULL : disk_it->second; 209 } 210 211 // DiskMountManager override. 212 virtual const MountPointMap& mount_points() const OVERRIDE { 213 return mount_points_; 214 } 215 216 // DiskMountManager override. 217 virtual bool AddDiskForTest(Disk* disk) OVERRIDE { 218 if (disks_.find(disk->device_path()) != disks_.end()) { 219 LOG(ERROR) << "Attempt to add a duplicate disk"; 220 return false; 221 } 222 223 disks_.insert(std::make_pair(disk->device_path(), disk)); 224 return true; 225 } 226 227 // DiskMountManager override. 228 // Corresponding disk should be added to the manager before this is called. 229 virtual bool AddMountPointForTest( 230 const MountPointInfo& mount_point) OVERRIDE { 231 if (mount_points_.find(mount_point.mount_path) != mount_points_.end()) { 232 LOG(ERROR) << "Attempt to add a duplicate mount point"; 233 return false; 234 } 235 if (mount_point.mount_type == chromeos::MOUNT_TYPE_DEVICE && 236 disks_.find(mount_point.source_path) == disks_.end()) { 237 LOG(ERROR) << "Device mount points must have a disk entry."; 238 return false; 239 } 240 241 mount_points_.insert(std::make_pair(mount_point.mount_path, mount_point)); 242 return true; 243 } 244 245 private: 246 struct UnmountDeviceRecursivelyCallbackData { 247 UnmountDeviceRecursivelyCallbackData( 248 const UnmountDeviceRecursivelyCallbackType& in_callback, 249 int in_num_pending_callbacks) 250 : callback(in_callback), 251 num_pending_callbacks(in_num_pending_callbacks) { 252 } 253 254 const UnmountDeviceRecursivelyCallbackType callback; 255 size_t num_pending_callbacks; 256 }; 257 258 // Unmounts all mount points whose source path is transitively parented by 259 // |mount_path|. 260 void UnmountChildMounts(const std::string& mount_path_in) { 261 std::string mount_path = mount_path_in; 262 // Let's make sure mount path has trailing slash. 263 if (mount_path[mount_path.length() - 1] != '/') 264 mount_path += '/'; 265 266 for (MountPointMap::iterator it = mount_points_.begin(); 267 it != mount_points_.end(); 268 ++it) { 269 if (StartsWithASCII(it->second.source_path, mount_path, 270 true /*case sensitive*/)) { 271 // TODO(tbarzic): Handle the case where this fails. 272 UnmountPath(it->second.mount_path, 273 UNMOUNT_OPTIONS_NONE, 274 UnmountPathCallback()); 275 } 276 } 277 } 278 279 // Callback for UnmountDeviceRecursively. 280 void OnUnmountDeviceRecursively( 281 UnmountDeviceRecursivelyCallbackData* cb_data, 282 bool success, 283 const std::string& mount_path) { 284 if (success) { 285 // Do standard processing for Unmount event. 286 OnUnmountPath(UnmountPathCallback(), true, mount_path); 287 VLOG(1) << mount_path << " unmounted."; 288 } 289 // This is safe as long as all callbacks are called on the same thread as 290 // UnmountDeviceRecursively. 291 cb_data->num_pending_callbacks--; 292 293 if (cb_data->num_pending_callbacks == 0) { 294 // This code has a problem that the |success| status used here is for the 295 // last "unmount" callback, but not whether all unmounting is succeeded. 296 // TODO(hidehiko): Fix the issue. 297 cb_data->callback.Run(success); 298 delete cb_data; 299 } 300 } 301 302 // Callback to handle MountCompleted signal and Mount method call failure. 303 void OnMountCompleted(MountError error_code, 304 const std::string& source_path, 305 MountType mount_type, 306 const std::string& mount_path) { 307 MountCondition mount_condition = MOUNT_CONDITION_NONE; 308 if (mount_type == MOUNT_TYPE_DEVICE) { 309 if (error_code == MOUNT_ERROR_UNKNOWN_FILESYSTEM) { 310 mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM; 311 } 312 if (error_code == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM) { 313 mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM; 314 } 315 } 316 const MountPointInfo mount_info(source_path, mount_path, mount_type, 317 mount_condition); 318 319 NotifyMountStatusUpdate(MOUNTING, error_code, mount_info); 320 321 // If the device is corrupted but it's still possible to format it, it will 322 // be fake mounted. 323 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) && 324 mount_points_.find(mount_info.mount_path) == mount_points_.end()) { 325 mount_points_.insert(MountPointMap::value_type(mount_info.mount_path, 326 mount_info)); 327 } 328 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) && 329 mount_info.mount_type == MOUNT_TYPE_DEVICE && 330 !mount_info.source_path.empty() && 331 !mount_info.mount_path.empty()) { 332 DiskMap::iterator iter = disks_.find(mount_info.source_path); 333 if (iter == disks_.end()) { 334 // disk might have been removed by now? 335 return; 336 } 337 Disk* disk = iter->second; 338 DCHECK(disk); 339 disk->set_mount_path(mount_info.mount_path); 340 } 341 } 342 343 // Callback for UnmountPath. 344 void OnUnmountPath(const UnmountPathCallback& callback, 345 bool success, 346 const std::string& mount_path) { 347 MountPointMap::iterator mount_points_it = mount_points_.find(mount_path); 348 if (mount_points_it == mount_points_.end()) { 349 // The path was unmounted, but not as a result of this unmount request, 350 // so return error. 351 if (!callback.is_null()) 352 callback.Run(MOUNT_ERROR_INTERNAL); 353 return; 354 } 355 356 NotifyMountStatusUpdate( 357 UNMOUNTING, 358 success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL, 359 MountPointInfo(mount_points_it->second.source_path, 360 mount_points_it->second.mount_path, 361 mount_points_it->second.mount_type, 362 mount_points_it->second.mount_condition)); 363 364 std::string path(mount_points_it->second.source_path); 365 if (success) 366 mount_points_.erase(mount_points_it); 367 368 DiskMap::iterator disk_iter = disks_.find(path); 369 if (disk_iter != disks_.end()) { 370 DCHECK(disk_iter->second); 371 if (success) 372 disk_iter->second->clear_mount_path(); 373 } 374 375 if (!callback.is_null()) 376 callback.Run(success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL); 377 } 378 379 void OnUnmountPathForFormat(const std::string& device_path, 380 MountError error_code) { 381 if (error_code == MOUNT_ERROR_NONE && 382 disks_.find(device_path) != disks_.end()) { 383 FormatUnmountedDevice(device_path); 384 } else { 385 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path); 386 } 387 } 388 389 // Starts device formatting. 390 void FormatUnmountedDevice(const std::string& device_path) { 391 DiskMap::const_iterator disk = disks_.find(device_path); 392 DCHECK(disk != disks_.end() && disk->second->mount_path().empty()); 393 394 const char kFormatVFAT[] = "vfat"; 395 cros_disks_client_->Format( 396 device_path, 397 kFormatVFAT, 398 base::Bind(&DiskMountManagerImpl::OnFormatStarted, 399 weak_ptr_factory_.GetWeakPtr(), 400 device_path), 401 base::Bind(&DiskMountManagerImpl::OnFormatCompleted, 402 weak_ptr_factory_.GetWeakPtr(), 403 FORMAT_ERROR_UNKNOWN, 404 device_path)); 405 } 406 407 // Callback for Format. 408 void OnFormatStarted(const std::string& device_path) { 409 NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path); 410 } 411 412 // Callback to handle FormatCompleted signal and Format method call failure. 413 void OnFormatCompleted(FormatError error_code, 414 const std::string& device_path) { 415 NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path); 416 } 417 418 // Callbcak for GetDeviceProperties. 419 void OnGetDeviceProperties(const DiskInfo& disk_info) { 420 // TODO(zelidrag): Find a better way to filter these out before we 421 // fetch the properties: 422 // Ignore disks coming from the device we booted the system from. 423 if (disk_info.on_boot_device()) 424 return; 425 426 LOG(WARNING) << "Found disk " << disk_info.device_path(); 427 // Delete previous disk info for this path: 428 bool is_new = true; 429 DiskMap::iterator iter = disks_.find(disk_info.device_path()); 430 if (iter != disks_.end()) { 431 delete iter->second; 432 disks_.erase(iter); 433 is_new = false; 434 } 435 Disk* disk = new Disk(disk_info.device_path(), 436 disk_info.mount_path(), 437 disk_info.system_path(), 438 disk_info.file_path(), 439 disk_info.label(), 440 disk_info.drive_label(), 441 disk_info.vendor_id(), 442 disk_info.vendor_name(), 443 disk_info.product_id(), 444 disk_info.product_name(), 445 disk_info.uuid(), 446 FindSystemPathPrefix(disk_info.system_path()), 447 disk_info.device_type(), 448 disk_info.total_size_in_bytes(), 449 disk_info.is_drive(), 450 disk_info.is_read_only(), 451 disk_info.has_media(), 452 disk_info.on_boot_device(), 453 disk_info.is_hidden()); 454 disks_.insert(std::make_pair(disk_info.device_path(), disk)); 455 NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, disk); 456 } 457 458 // Callbcak for RequestMountInfo. 459 void OnRequestMountInfo(const std::vector<std::string>& devices) { 460 std::set<std::string> current_device_set; 461 if (!devices.empty()) { 462 // Initiate properties fetch for all removable disks, 463 for (size_t i = 0; i < devices.size(); i++) { 464 current_device_set.insert(devices[i]); 465 // Initiate disk property retrieval for each relevant device path. 466 cros_disks_client_->GetDeviceProperties( 467 devices[i], 468 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, 469 weak_ptr_factory_.GetWeakPtr()), 470 base::Bind(&base::DoNothing)); 471 } 472 } 473 // Search and remove disks that are no longer present. 474 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) { 475 if (current_device_set.find(iter->first) == current_device_set.end()) { 476 Disk* disk = iter->second; 477 NotifyDiskStatusUpdate(DISK_REMOVED, disk); 478 delete iter->second; 479 disks_.erase(iter++); 480 } else { 481 ++iter; 482 } 483 } 484 } 485 486 // Callback to handle mount event signals. 487 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { 488 // Take a copy of the argument so we can modify it below. 489 std::string device_path = device_path_arg; 490 switch (event) { 491 case CROS_DISKS_DISK_ADDED: { 492 cros_disks_client_->GetDeviceProperties( 493 device_path, 494 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, 495 weak_ptr_factory_.GetWeakPtr()), 496 base::Bind(&base::DoNothing)); 497 break; 498 } 499 case CROS_DISKS_DISK_REMOVED: { 500 // Search and remove disks that are no longer present. 501 DiskMountManager::DiskMap::iterator iter = disks_.find(device_path); 502 if (iter != disks_.end()) { 503 Disk* disk = iter->second; 504 NotifyDiskStatusUpdate(DISK_REMOVED, disk); 505 delete iter->second; 506 disks_.erase(iter); 507 } 508 break; 509 } 510 case CROS_DISKS_DEVICE_ADDED: { 511 system_path_prefixes_.insert(device_path); 512 NotifyDeviceStatusUpdate(DEVICE_ADDED, device_path); 513 break; 514 } 515 case CROS_DISKS_DEVICE_REMOVED: { 516 system_path_prefixes_.erase(device_path); 517 NotifyDeviceStatusUpdate(DEVICE_REMOVED, device_path); 518 break; 519 } 520 case CROS_DISKS_DEVICE_SCANNED: { 521 NotifyDeviceStatusUpdate(DEVICE_SCANNED, device_path); 522 break; 523 } 524 default: { 525 LOG(ERROR) << "Unknown event: " << event; 526 } 527 } 528 } 529 530 // Notifies all observers about disk status update. 531 void NotifyDiskStatusUpdate(DiskEvent event, 532 const Disk* disk) { 533 FOR_EACH_OBSERVER(Observer, observers_, OnDiskEvent(event, disk)); 534 } 535 536 // Notifies all observers about device status update. 537 void NotifyDeviceStatusUpdate(DeviceEvent event, 538 const std::string& device_path) { 539 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceEvent(event, device_path)); 540 } 541 542 // Notifies all observers about mount completion. 543 void NotifyMountStatusUpdate(MountEvent event, 544 MountError error_code, 545 const MountPointInfo& mount_info) { 546 FOR_EACH_OBSERVER(Observer, observers_, 547 OnMountEvent(event, error_code, mount_info)); 548 } 549 550 void NotifyFormatStatusUpdate(FormatEvent event, 551 FormatError error_code, 552 const std::string& device_path) { 553 FOR_EACH_OBSERVER(Observer, observers_, 554 OnFormatEvent(event, error_code, device_path)); 555 } 556 557 // Finds system path prefix from |system_path|. 558 const std::string& FindSystemPathPrefix(const std::string& system_path) { 559 if (system_path.empty()) 560 return base::EmptyString(); 561 for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin(); 562 it != system_path_prefixes_.end(); 563 ++it) { 564 const std::string& prefix = *it; 565 if (StartsWithASCII(system_path, prefix, true)) 566 return prefix; 567 } 568 return base::EmptyString(); 569 } 570 571 // Mount event change observers. 572 ObserverList<Observer> observers_; 573 574 CrosDisksClient* cros_disks_client_; 575 576 // The list of disks found. 577 DiskMountManager::DiskMap disks_; 578 579 DiskMountManager::MountPointMap mount_points_; 580 581 typedef std::set<std::string> SystemPathPrefixSet; 582 SystemPathPrefixSet system_path_prefixes_; 583 584 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; 585 586 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); 587}; 588 589} // namespace 590 591DiskMountManager::Disk::Disk(const std::string& device_path, 592 const std::string& mount_path, 593 const std::string& system_path, 594 const std::string& file_path, 595 const std::string& device_label, 596 const std::string& drive_label, 597 const std::string& vendor_id, 598 const std::string& vendor_name, 599 const std::string& product_id, 600 const std::string& product_name, 601 const std::string& fs_uuid, 602 const std::string& system_path_prefix, 603 DeviceType device_type, 604 uint64 total_size_in_bytes, 605 bool is_parent, 606 bool is_read_only, 607 bool has_media, 608 bool on_boot_device, 609 bool is_hidden) 610 : device_path_(device_path), 611 mount_path_(mount_path), 612 system_path_(system_path), 613 file_path_(file_path), 614 device_label_(device_label), 615 drive_label_(drive_label), 616 vendor_id_(vendor_id), 617 vendor_name_(vendor_name), 618 product_id_(product_id), 619 product_name_(product_name), 620 fs_uuid_(fs_uuid), 621 system_path_prefix_(system_path_prefix), 622 device_type_(device_type), 623 total_size_in_bytes_(total_size_in_bytes), 624 is_parent_(is_parent), 625 is_read_only_(is_read_only), 626 has_media_(has_media), 627 on_boot_device_(on_boot_device), 628 is_hidden_(is_hidden) { 629} 630 631DiskMountManager::Disk::~Disk() {} 632 633bool DiskMountManager::AddDiskForTest(Disk* disk) { 634 return false; 635} 636 637bool DiskMountManager::AddMountPointForTest(const MountPointInfo& mount_point) { 638 return false; 639} 640 641// static 642std::string DiskMountManager::MountConditionToString(MountCondition condition) { 643 switch (condition) { 644 case MOUNT_CONDITION_NONE: 645 return ""; 646 case MOUNT_CONDITION_UNKNOWN_FILESYSTEM: 647 return "unknown_filesystem"; 648 case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM: 649 return "unsupported_filesystem"; 650 default: 651 NOTREACHED(); 652 } 653 return ""; 654} 655 656// static 657std::string DiskMountManager::DeviceTypeToString(DeviceType type) { 658 switch (type) { 659 case DEVICE_TYPE_USB: 660 return "usb"; 661 case DEVICE_TYPE_SD: 662 return "sd"; 663 case DEVICE_TYPE_OPTICAL_DISC: 664 return "optical"; 665 case DEVICE_TYPE_MOBILE: 666 return "mobile"; 667 default: 668 return "unknown"; 669 } 670} 671 672// static 673void DiskMountManager::Initialize() { 674 if (g_disk_mount_manager) { 675 LOG(WARNING) << "DiskMountManager was already initialized"; 676 return; 677 } 678 g_disk_mount_manager = new DiskMountManagerImpl(); 679 VLOG(1) << "DiskMountManager initialized"; 680} 681 682// static 683void DiskMountManager::InitializeForTesting( 684 DiskMountManager* disk_mount_manager) { 685 if (g_disk_mount_manager) { 686 LOG(WARNING) << "DiskMountManager was already initialized"; 687 return; 688 } 689 g_disk_mount_manager = disk_mount_manager; 690 VLOG(1) << "DiskMountManager initialized"; 691} 692 693// static 694void DiskMountManager::Shutdown() { 695 if (!g_disk_mount_manager) { 696 LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager"; 697 return; 698 } 699 delete g_disk_mount_manager; 700 g_disk_mount_manager = NULL; 701 VLOG(1) << "DiskMountManager Shutdown completed"; 702} 703 704// static 705DiskMountManager* DiskMountManager::GetInstance() { 706 return g_disk_mount_manager; 707} 708 709} // namespace disks 710} // namespace chromeos 711