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