| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/cros/mount_library.h" | 5 #include "chrome/browser/chromeos/cros/mount_library.h" |
| 6 | 6 |
| 7 #include <set> |
| 8 |
| 7 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 8 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 9 #include "chrome/browser/chromeos/cros/cros_library.h" | 11 #include "chrome/browser/chromeos/cros/cros_library.h" |
| 10 #include "content/browser/browser_thread.h" | 12 #include "content/browser/browser_thread.h" |
| 11 | 13 |
| 12 namespace chromeos { | 14 namespace chromeos { |
| 13 | 15 |
| 14 class MountLibraryImpl : public MountLibrary { | 16 class MountLibraryImpl : public MountLibrary { |
| 15 public: | 17 public: |
| 16 MountLibraryImpl() : mount_status_connection_(NULL) { | 18 MountLibraryImpl() : mount_status_connection_(NULL) { |
| 17 if (CrosLibrary::Get()->EnsureLoaded()) { | 19 if (CrosLibrary::Get()->EnsureLoaded()) |
| 18 Init(); | 20 Init(); |
| 21 else |
| 22 LOG(ERROR) << "Cros Library has not been loaded"; |
| 23 } |
| 24 |
| 25 virtual ~MountLibraryImpl() { |
| 26 if (mount_status_connection_) |
| 27 DisconnectMountEventMonitor(mount_status_connection_); |
| 28 } |
| 29 |
| 30 // MountLibrary overrides. |
| 31 virtual void AddObserver(Observer* observer) OVERRIDE { |
| 32 observers_.AddObserver(observer); |
| 33 } |
| 34 |
| 35 virtual void RemoveObserver(Observer* observer) OVERRIDE { |
| 36 observers_.RemoveObserver(observer); |
| 37 } |
| 38 |
| 39 virtual void MountPath(const char* device_path) OVERRIDE { |
| 40 MountRemovableDevice(device_path, |
| 41 &MountLibraryImpl::MountRemovableDeviceCallback, |
| 42 this); |
| 43 } |
| 44 |
| 45 virtual void UnmountPath(const char* device_path) OVERRIDE { |
| 46 UnmountRemovableDevice(device_path, |
| 47 &MountLibraryImpl::UnmountRemovableDeviceCallback, |
| 48 this); |
| 49 } |
| 50 |
| 51 virtual void RequestMountInfoRefresh() OVERRIDE { |
| 52 RequestMountInfo(&MountLibraryImpl::RequestMountInfoCallback, |
| 53 this); |
| 54 } |
| 55 |
| 56 virtual void RefreshDiskProperties(const Disk* disk) OVERRIDE { |
| 57 DCHECK(disk); |
| 58 GetDiskProperties(disk->device_path().c_str(), |
| 59 &MountLibraryImpl::GetDiskPropertiesCallback, |
| 60 this); |
| 61 } |
| 62 |
| 63 const DiskMap& disks() const OVERRIDE { return disks_; } |
| 64 |
| 65 private: |
| 66 |
| 67 // Callback for MountRemovableDevice method. |
| 68 static void MountRemovableDeviceCallback(void* object, |
| 69 const char* device_path, |
| 70 const char* mount_path, |
| 71 MountMethodErrorType error, |
| 72 const char* error_message) { |
| 73 DCHECK(object); |
| 74 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object); |
| 75 self->OnMountRemovableDevice(device_path, |
| 76 mount_path, |
| 77 error, |
| 78 error_message); |
| 79 } |
| 80 |
| 81 // Callback for UnmountRemovableDevice method. |
| 82 static void UnmountRemovableDeviceCallback(void* object, |
| 83 const char* device_path, |
| 84 const char* mount_path, |
| 85 MountMethodErrorType error, |
| 86 const char* error_message) { |
| 87 DCHECK(object); |
| 88 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object); |
| 89 self->OnUnmountRemovableDevice(device_path, |
| 90 error, |
| 91 error_message); |
| 92 } |
| 93 |
| 94 // Callback for disk information retrieval calls. |
| 95 static void GetDiskPropertiesCallback(void* object, |
| 96 const char* device_path, |
| 97 const DiskInfo* disk, |
| 98 MountMethodErrorType error, |
| 99 const char* error_message) { |
| 100 DCHECK(object); |
| 101 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object); |
| 102 self->OnGetDiskProperties(device_path, |
| 103 disk, |
| 104 error, |
| 105 error_message); |
| 106 } |
| 107 |
| 108 // Callback for RequestMountInfo call. |
| 109 static void RequestMountInfoCallback(void* object, |
| 110 const char** devices, |
| 111 size_t device_len, |
| 112 MountMethodErrorType error, |
| 113 const char* error_message) { |
| 114 DCHECK(object); |
| 115 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object); |
| 116 self->OnRequestMountInfo(devices, |
| 117 device_len, |
| 118 error, |
| 119 error_message); |
| 120 } |
| 121 |
| 122 // This method will receive events that are caused by drive status changes. |
| 123 static void MonitorMountEventsHandler(void* object, |
| 124 MountEventType evt, |
| 125 const char* device_path) { |
| 126 DCHECK(object); |
| 127 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object); |
| 128 self->OnMountEvent(evt, device_path); |
| 129 } |
| 130 |
| 131 |
| 132 void OnMountRemovableDevice(const char* device_path, |
| 133 const char* mount_path, |
| 134 MountMethodErrorType error, |
| 135 const char* error_message) { |
| 136 DCHECK(device_path); |
| 137 DCHECK(mount_path); |
| 138 if (error == MOUNT_METHOD_ERROR_NONE && device_path && mount_path) { |
| 139 std::string path(device_path); |
| 140 DiskMap::iterator iter = disks_.find(path); |
| 141 if (iter == disks_.end()) { |
| 142 // disk might have been removed by now? |
| 143 return; |
| 144 } |
| 145 Disk* disk = iter->second; |
| 146 DCHECK(disk); |
| 147 disk->set_mount_path(mount_path); |
| 148 FireDiskStatusUpdate(MOUNT_DISK_MOUNTED, disk); |
| 19 } else { | 149 } else { |
| 20 LOG(ERROR) << "Cros Library has not been loaded"; | 150 LOG(WARNING) << "Mount request failed for device " |
| 21 } | 151 << device_path << ", with error: " |
| 22 } | 152 << (error_message ? error_message : "Unknown"); |
| 23 | 153 } |
| 24 ~MountLibraryImpl() { | 154 } |
| 25 if (mount_status_connection_) { | 155 |
| 26 DisconnectMountStatus(mount_status_connection_); | 156 void OnUnmountRemovableDevice(const char* device_path, |
| 27 } | 157 MountMethodErrorType error, |
| 28 } | 158 const char* error_message) { |
| 29 | 159 DCHECK(device_path); |
| 30 void AddObserver(Observer* observer) { | 160 if (error == MOUNT_METHOD_ERROR_NONE && device_path) { |
| 31 observers_.AddObserver(observer); | 161 std::string path(device_path); |
| 32 } | 162 DiskMap::iterator iter = disks_.find(path); |
| 33 | 163 if (iter == disks_.end()) { |
| 34 void RemoveObserver(Observer* observer) { | 164 // disk might have been removed by now? |
| 35 observers_.RemoveObserver(observer); | 165 return; |
| 36 } | 166 } |
| 37 | 167 Disk* disk = iter->second; |
| 38 bool MountPath(const char* device_path) { | 168 DCHECK(disk); |
| 39 return MountDevicePath(device_path); | 169 disk->clear_mount_path(); |
| 40 } | 170 FireDiskStatusUpdate(MOUNT_DISK_UNMOUNTED, disk); |
| 41 | 171 } else { |
| 42 bool IsBootPath(const char* device_path) { | 172 LOG(WARNING) << "Unmount request failed for device " |
| 43 return IsBootDevicePath(device_path); | 173 << device_path << ", with error: " |
| 44 } | 174 << (error_message ? error_message : "Unknown"); |
| 45 | 175 } |
| 46 const DiskVector& disks() const { return disks_; } | 176 } |
| 47 | 177 |
| 48 private: | 178 void OnGetDiskProperties(const char* device_path, |
| 49 void ParseDisks(const MountStatus& status) { | 179 const DiskInfo* disk, |
| 50 disks_.clear(); | 180 MountMethodErrorType error, |
| 51 for (int i = 0; i < status.size; i++) { | 181 const char* error_message) { |
| 182 DCHECK(device_path); |
| 183 if (error == MOUNT_METHOD_ERROR_NONE && device_path) { |
| 184 // TODO(zelidrag): Find a better way to filter these out before we |
| 185 // fetch the properties: |
| 186 // Ignore disks coming from the device we booted the system from. |
| 187 if (disk->on_boot_device()) |
| 188 return; |
| 189 |
| 190 LOG(WARNING) << "Found disk " << device_path; |
| 191 // Delete previous disk info for this path: |
| 192 bool is_new = true; |
| 193 std::string device_path_string(device_path); |
| 194 DiskMap::iterator iter = disks_.find(device_path_string); |
| 195 if (iter != disks_.end()) { |
| 196 delete iter->second; |
| 197 disks_.erase(iter); |
| 198 is_new = false; |
| 199 } |
| 52 std::string path; | 200 std::string path; |
| 53 std::string mountpath; | 201 std::string mountpath; |
| 54 std::string systempath; | 202 std::string systempath; |
| 55 bool parent; | 203 if (disk->path() != NULL) |
| 56 bool hasmedia; | 204 path = disk->path(); |
| 57 if (status.disks[i].path != NULL) { | 205 |
| 58 path = status.disks[i].path; | 206 if (disk->mount_path() != NULL) |
| 59 } | 207 mountpath = disk->mount_path(); |
| 60 if (status.disks[i].mountpath != NULL) { | 208 |
| 61 mountpath = status.disks[i].mountpath; | 209 if (disk->system_path() != NULL) |
| 62 } | 210 systempath = disk->system_path(); |
| 63 if (status.disks[i].systempath != NULL) { | 211 |
| 64 systempath = status.disks[i].systempath; | 212 Disk* new_disk = new Disk(path, |
| 65 } | 213 mountpath, |
| 66 parent = status.disks[i].isparent; | 214 systempath, |
| 67 hasmedia = status.disks[i].hasmedia; | 215 disk->is_drive(), |
| 68 disks_.push_back(Disk(path, | 216 disk->has_media(), |
| 69 mountpath, | 217 disk->on_boot_device()); |
| 70 systempath, | 218 disks_.insert( |
| 71 parent, | 219 std::pair<std::string, Disk*>(device_path_string, new_disk)); |
| 72 hasmedia)); | 220 FireDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED, |
| 73 } | 221 new_disk); |
| 74 } | 222 } else { |
| 75 | 223 LOG(WARNING) << "Property retrieval request failed for device " |
| 76 static void MountStatusChangedHandler(void* object, | 224 << device_path << ", with error: " |
| 77 const MountStatus& status, | 225 << (error_message ? error_message : "Unknown"); |
| 78 MountEventType evt, | 226 } |
| 79 const char* path) { | 227 } |
| 80 MountLibraryImpl* mount = static_cast<MountLibraryImpl*>(object); | 228 |
| 81 std::string devicepath = path; | 229 void OnRequestMountInfo(const char** devices, |
| 82 mount->ParseDisks(status); | 230 size_t devices_len, |
| 83 mount->UpdateMountStatus(status, evt, devicepath); | 231 MountMethodErrorType error, |
| 232 const char* error_message) { |
| 233 std::set<std::string> current_device_set; |
| 234 if (error == MOUNT_METHOD_ERROR_NONE && devices && devices_len) { |
| 235 // Initiate properties fetch for all removable disks, |
| 236 bool found_disk = false; |
| 237 for (size_t i = 0; i < devices_len; i++) { |
| 238 if (!devices[i]) { |
| 239 NOTREACHED(); |
| 240 continue; |
| 241 } |
| 242 current_device_set.insert(std::string(devices[i])); |
| 243 found_disk = true; |
| 244 // Initiate disk property retrieval for each relevant device path. |
| 245 GetDiskProperties(devices[i], |
| 246 &MountLibraryImpl::GetDiskPropertiesCallback, |
| 247 this); |
| 248 } |
| 249 } else if (error != MOUNT_METHOD_ERROR_NONE) { |
| 250 LOG(WARNING) << "Request mount info retrieval request failed with error: " |
| 251 << (error_message ? error_message : "Unknown"); |
| 252 } |
| 253 // Search and remove disks that are no longer present. |
| 254 for (MountLibrary::DiskMap::iterator iter = disks_.begin(); |
| 255 iter != disks_.end(); ) { |
| 256 if (current_device_set.find(iter->first) == current_device_set.end()) { |
| 257 Disk* disk = iter->second; |
| 258 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk); |
| 259 delete iter->second; |
| 260 disks_.erase(iter++); |
| 261 } else { |
| 262 ++iter; |
| 263 } |
| 264 } |
| 265 } |
| 266 |
| 267 void OnMountEvent(MountEventType evt, |
| 268 const char* device_path) { |
| 269 if (!device_path) |
| 270 return; |
| 271 MountLibraryEventType type; |
| 272 switch (evt) { |
| 273 case DISK_ADDED: |
| 274 case DISK_CHANGED: { |
| 275 GetDiskProperties(device_path, |
| 276 &MountLibraryImpl::GetDiskPropertiesCallback, |
| 277 this); |
| 278 return; |
| 279 } |
| 280 case DISK_REMOVED: { |
| 281 // Search and remove disks that are no longer present. |
| 282 MountLibrary::DiskMap::iterator iter = |
| 283 disks_.find(std::string(device_path)); |
| 284 if (iter != disks_.end()) { |
| 285 Disk* disk = iter->second; |
| 286 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk); |
| 287 delete iter->second; |
| 288 disks_.erase(iter); |
| 289 } |
| 290 return; |
| 291 } |
| 292 case DEVICE_ADDED: { |
| 293 type = MOUNT_DEVICE_ADDED; |
| 294 break; |
| 295 } |
| 296 case DEVICE_REMOVED: { |
| 297 type = MOUNT_DEVICE_REMOVED; |
| 298 break; |
| 299 } |
| 300 case DEVICE_SCANNED: { |
| 301 type = MOUNT_DEVICE_SCANNED; |
| 302 break; |
| 303 } |
| 304 } |
| 305 FireDeviceStatusUpdate(type, std::string(device_path)); |
| 84 } | 306 } |
| 85 | 307 |
| 86 void Init() { | 308 void Init() { |
| 87 // Getting the monitor status so that the daemon starts up. | 309 // Getting the monitor status so that the daemon starts up. |
| 88 MountStatus* mount = RetrieveMountInformation(); | 310 mount_status_connection_ = MonitorMountEvents( |
| 89 if (!mount) { | 311 &MonitorMountEventsHandler, this); |
| 90 LOG(ERROR) << "Failed to retrieve mount information"; | 312 } |
| 91 return; | 313 |
| 92 } | 314 void FireDiskStatusUpdate(MountLibraryEventType evt, |
| 93 ParseDisks(*mount); | 315 const Disk* disk) { |
| 94 FreeMountStatus(mount); | |
| 95 | |
| 96 mount_status_connection_ = MonitorMountStatus( | |
| 97 &MountStatusChangedHandler, this); | |
| 98 } | |
| 99 | |
| 100 void UpdateMountStatus(const MountStatus& status, | |
| 101 MountEventType evt, | |
| 102 const std::string& path) { | |
| 103 // Make sure we run on UI thread. | 316 // Make sure we run on UI thread. |
| 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 105 | |
| 106 FOR_EACH_OBSERVER( | 318 FOR_EACH_OBSERVER( |
| 107 Observer, observers_, MountChanged(this, evt, path)); | 319 Observer, observers_, DiskChanged(evt, disk)); |
| 108 } | 320 } |
| 321 |
| 322 void FireDeviceStatusUpdate(MountLibraryEventType evt, |
| 323 const std::string& device_path) { |
| 324 // Make sure we run on UI thread. |
| 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 326 FOR_EACH_OBSERVER( |
| 327 Observer, observers_, DeviceChanged(evt, device_path)); |
| 328 } |
| 329 |
| 330 // Mount event change observers. |
| 109 ObserverList<Observer> observers_; | 331 ObserverList<Observer> observers_; |
| 110 | 332 |
| 111 // A reference to the mount api, to allow callbacks when the mount | 333 // A reference to the mount api, to allow callbacks when the mount |
| 112 // status changes. | 334 // status changes. |
| 113 MountStatusConnection mount_status_connection_; | 335 MountEventConnection mount_status_connection_; |
| 114 | 336 |
| 115 // The list of disks found. | 337 // The list of disks found. |
| 116 DiskVector disks_; | 338 MountLibrary::DiskMap disks_; |
| 117 | 339 |
| 118 DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl); | 340 DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl); |
| 119 }; | 341 }; |
| 120 | 342 |
| 121 class MountLibraryStubImpl : public MountLibrary { | 343 class MountLibraryStubImpl : public MountLibrary { |
| 122 public: | 344 public: |
| 123 MountLibraryStubImpl() {} | 345 MountLibraryStubImpl() {} |
| 124 virtual ~MountLibraryStubImpl() {} | 346 virtual ~MountLibraryStubImpl() {} |
| 125 | 347 |
| 126 // MountLibrary overrides. | 348 // MountLibrary overrides. |
| 127 virtual void AddObserver(Observer* observer) {} | 349 virtual void AddObserver(Observer* observer) OVERRIDE {} |
| 128 virtual void RemoveObserver(Observer* observer) {} | 350 virtual void RemoveObserver(Observer* observer) OVERRIDE {} |
| 129 virtual const DiskVector& disks() const { return disks_; } | 351 virtual const DiskMap& disks() const OVERRIDE { return disks_; } |
| 130 virtual bool MountPath(const char* device_path) { return false; } | 352 virtual void RequestMountInfoRefresh() OVERRIDE {} |
| 131 virtual bool IsBootPath(const char* device_path) { return true; } | 353 virtual void MountPath(const char* device_path) OVERRIDE {} |
| 354 virtual void UnmountPath(const char* device_path) OVERRIDE {} |
| 355 virtual bool IsBootPath(const char* device_path) OVERRIDE { return true; } |
| 132 | 356 |
| 133 private: | 357 private: |
| 134 // The list of disks found. | 358 // The list of disks found. |
| 135 DiskVector disks_; | 359 DiskMap disks_; |
| 136 | 360 |
| 137 DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl); | 361 DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl); |
| 138 }; | 362 }; |
| 139 | 363 |
| 140 // static | 364 // static |
| 141 MountLibrary* MountLibrary::GetImpl(bool stub) { | 365 MountLibrary* MountLibrary::GetImpl(bool stub) { |
| 142 if (stub) | 366 if (stub) |
| 143 return new MountLibraryStubImpl(); | 367 return new MountLibraryStubImpl(); |
| 144 else | 368 else |
| 145 return new MountLibraryImpl(); | 369 return new MountLibraryImpl(); |
| 146 } | 370 } |
| 147 | 371 |
| 148 } // namespace chromeos | 372 } // namespace chromeos |
| 149 | 373 |
| 150 // Allows InvokeLater without adding refcounting. This class is a Singleton and | 374 // Allows InvokeLater without adding refcounting. This class is a Singleton and |
| 151 // won't be deleted until it's last InvokeLater is run. | 375 // won't be deleted until it's last InvokeLater is run. |
| 152 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl); | 376 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl); |
| 153 | 377 |
| OLD | NEW |