Chromium Code Reviews| 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 | |
|
stevenjb
2011/03/16 22:52:55
partial comment
zel
2011/03/17 01:00:30
Done.
| |
| 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; | |
|
stevenjb
2011/03/16 22:52:55
-> VLOG(1)
| |
| 191 // Delete previous disk info for this path: | |
| 192 bool is_new = true; | |
| 193 DiskMap::iterator iter = disks_.find(std::string(device_path)); | |
| 194 if (iter != disks_.end()) { | |
| 195 delete iter->second; | |
| 196 disks_.erase(iter); | |
| 197 is_new = false; | |
| 198 } | |
| 52 std::string path; | 199 std::string path; |
| 53 std::string mountpath; | 200 std::string mountpath; |
| 54 std::string systempath; | 201 std::string systempath; |
| 55 bool parent; | 202 if (disk->path() != NULL) { |
| 56 bool hasmedia; | 203 path = disk->path(); |
| 57 if (status.disks[i].path != NULL) { | 204 } |
|
stevenjb
2011/03/16 22:52:55
nit: { } not needed
zel
2011/03/17 01:00:30
Done.
| |
| 58 path = status.disks[i].path; | 205 if (disk->mount_path() != NULL) { |
| 59 } | 206 mountpath = disk->mount_path(); |
| 60 if (status.disks[i].mountpath != NULL) { | 207 } |
|
stevenjb
2011/03/16 22:52:55
nit: { } not needed
zel
2011/03/17 01:00:30
Done.
| |
| 61 mountpath = status.disks[i].mountpath; | 208 if (disk->system_path() != NULL) { |
| 62 } | 209 systempath = disk->system_path(); |
| 63 if (status.disks[i].systempath != NULL) { | 210 } |
|
stevenjb
2011/03/16 22:52:55
nit: { } not needed
zel
2011/03/17 01:00:30
Done.
| |
| 64 systempath = status.disks[i].systempath; | 211 Disk* new_disk = new Disk(path, |
| 65 } | 212 mountpath, |
| 66 parent = status.disks[i].isparent; | 213 systempath, |
| 67 hasmedia = status.disks[i].hasmedia; | 214 disk->is_drive(), |
| 68 disks_.push_back(Disk(path, | 215 disk->has_media(), |
| 69 mountpath, | 216 disk->on_boot_device()); |
|
stevenjb
2011/03/16 22:52:55
Is it valid for a Disk to have any empty path, mou
zel
2011/03/17 01:00:30
Yes, mount path can be empty. We actually kick off
| |
| 70 systempath, | 217 disks_.insert( |
| 71 parent, | 218 std::pair<std::string, Disk*>(std::string(device_path), new_disk)); |
|
stevenjb
2011/03/16 22:52:55
nit: second std::string conversion of device_path
zel
2011/03/17 01:00:30
Done.
| |
| 72 hasmedia)); | 219 FireDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED, |
| 73 } | 220 new_disk); |
| 74 } | 221 } else { |
| 75 | 222 LOG(WARNING) << "Property retrieval request failed for device " |
| 76 static void MountStatusChangedHandler(void* object, | 223 << device_path << ", with error: " |
| 77 const MountStatus& status, | 224 << (error_message ? error_message : "Unknown"); |
| 78 MountEventType evt, | 225 } |
| 79 const char* path) { | 226 } |
| 80 MountLibraryImpl* mount = static_cast<MountLibraryImpl*>(object); | 227 |
| 81 std::string devicepath = path; | 228 void OnRequestMountInfo(const char** devices, |
| 82 mount->ParseDisks(status); | 229 size_t device_len, |
|
stevenjb
2011/03/16 22:52:55
nit: devices_len
zel
2011/03/17 01:00:30
Done.
| |
| 83 mount->UpdateMountStatus(status, evt, devicepath); | 230 MountMethodErrorType error, |
| 231 const char* error_message) { | |
| 232 std::set<std::string> current_device_set; | |
| 233 if (error == MOUNT_METHOD_ERROR_NONE && devices && device_len) { | |
| 234 // Initiate properties fetch for all removable disks, | |
| 235 bool found_disk = false; | |
| 236 for (size_t i = 0; i < device_len; i++) { | |
|
stevenjb
2011/03/16 22:52:55
DCHECK(devices[i]) or if (!devices[i]) continue;
zel
2011/03/17 01:00:30
Done.
| |
| 237 current_device_set.insert(std::string(devices[i])); | |
| 238 found_disk = true; | |
| 239 // Initiate disk property retrieval for each relevant device path. | |
| 240 GetDiskProperties(devices[i], | |
| 241 &MountLibraryImpl::GetDiskPropertiesCallback, | |
| 242 this); | |
| 243 } | |
| 244 } else if (error != MOUNT_METHOD_ERROR_NONE) { | |
| 245 LOG(WARNING) << "Request mount info retrieval request failed with error: " | |
| 246 << (error_message ? error_message : "Unknown"); | |
| 247 } | |
| 248 // Search and remove disks that are no longer present. | |
| 249 for (MountLibrary::DiskMap::iterator iter = disks_.begin(); | |
| 250 iter != disks_.end(); | |
| 251 ++iter) { | |
|
stevenjb
2011/03/16 22:52:55
++iter here and erase(iter++) below; remove this a
zel
2011/03/17 01:00:30
Good catch. Done.
| |
| 252 if (current_device_set.find(iter->first) == current_device_set.end()) { | |
| 253 Disk* disk = iter->second; | |
| 254 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk); | |
| 255 delete iter->second; | |
| 256 disks_.erase(iter++); | |
| 257 } | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 void OnMountEvent(MountEventType evt, | |
| 262 const char* device_path) { | |
| 263 if (!device_path) | |
| 264 return; | |
| 265 MountLibraryEventType type; | |
| 266 switch (evt) { | |
| 267 case DISK_ADDED: | |
| 268 case DISK_CHANGED: { | |
| 269 GetDiskProperties(device_path, | |
| 270 &MountLibraryImpl::GetDiskPropertiesCallback, | |
| 271 this); | |
| 272 return; | |
| 273 } | |
| 274 case DISK_REMOVED: { | |
| 275 // Search and remove disks that are no longer present. | |
| 276 MountLibrary::DiskMap::iterator iter = | |
| 277 disks_.find(std::string(device_path)); | |
| 278 if (iter != disks_.end()) { | |
| 279 Disk* disk = iter->second; | |
| 280 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk); | |
| 281 delete iter->second; | |
| 282 disks_.erase(iter++); | |
|
stevenjb
2011/03/16 22:52:55
++ unnecessary
zel
2011/03/17 01:00:30
Done.
| |
| 283 } | |
| 284 return; | |
| 285 } | |
| 286 case DEVICE_ADDED: { | |
| 287 type = MOUNT_DEVICE_ADDED; | |
| 288 break; | |
| 289 } | |
| 290 case DEVICE_REMOVED: { | |
| 291 type = MOUNT_DEVICE_REMOVED; | |
| 292 break; | |
| 293 } | |
| 294 case DEVICE_SCANNED: { | |
| 295 type = MOUNT_DEVICE_SCANNED; | |
| 296 break; | |
| 297 } | |
| 298 } | |
| 299 FireDeviceStatusUpdate(type, std::string(device_path)); | |
| 84 } | 300 } |
| 85 | 301 |
| 86 void Init() { | 302 void Init() { |
| 87 // Getting the monitor status so that the daemon starts up. | 303 // Getting the monitor status so that the daemon starts up. |
| 88 MountStatus* mount = RetrieveMountInformation(); | 304 mount_status_connection_ = MonitorMountEvents( |
| 89 if (!mount) { | 305 &MonitorMountEventsHandler, this); |
| 90 LOG(ERROR) << "Failed to retrieve mount information"; | 306 } |
| 91 return; | 307 |
| 92 } | 308 void FireDiskStatusUpdate(MountLibraryEventType evt, |
| 93 ParseDisks(*mount); | 309 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. | 310 // Make sure we run on UI thread. |
| 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 105 | |
| 106 FOR_EACH_OBSERVER( | 312 FOR_EACH_OBSERVER( |
| 107 Observer, observers_, MountChanged(this, evt, path)); | 313 Observer, observers_, DiskChanged(evt, disk)); |
| 108 } | 314 } |
| 315 | |
| 316 void FireDeviceStatusUpdate(MountLibraryEventType evt, | |
| 317 const std::string& device_path) { | |
| 318 // Make sure we run on UI thread. | |
| 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 320 FOR_EACH_OBSERVER( | |
| 321 Observer, observers_, DeviceChanged(evt, device_path)); | |
| 322 } | |
| 323 | |
| 324 // Mount event change observers. | |
| 109 ObserverList<Observer> observers_; | 325 ObserverList<Observer> observers_; |
| 110 | 326 |
| 111 // A reference to the mount api, to allow callbacks when the mount | 327 // A reference to the mount api, to allow callbacks when the mount |
| 112 // status changes. | 328 // status changes. |
| 113 MountStatusConnection mount_status_connection_; | 329 MountEventConnection mount_status_connection_; |
| 114 | 330 |
| 115 // The list of disks found. | 331 // The list of disks found. |
| 116 DiskVector disks_; | 332 MountLibrary::DiskMap disks_; |
| 117 | 333 |
| 118 DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl); | 334 DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl); |
| 119 }; | 335 }; |
| 120 | 336 |
| 121 class MountLibraryStubImpl : public MountLibrary { | 337 class MountLibraryStubImpl : public MountLibrary { |
| 122 public: | 338 public: |
| 123 MountLibraryStubImpl() {} | 339 MountLibraryStubImpl() {} |
| 124 virtual ~MountLibraryStubImpl() {} | 340 virtual ~MountLibraryStubImpl() {} |
| 125 | 341 |
| 126 // MountLibrary overrides. | 342 // MountLibrary overrides. |
| 127 virtual void AddObserver(Observer* observer) {} | 343 virtual void AddObserver(Observer* observer) OVERRIDE {} |
| 128 virtual void RemoveObserver(Observer* observer) {} | 344 virtual void RemoveObserver(Observer* observer) OVERRIDE {} |
| 129 virtual const DiskVector& disks() const { return disks_; } | 345 virtual const DiskMap& disks() const OVERRIDE { return disks_; } |
| 130 virtual bool MountPath(const char* device_path) { return false; } | 346 virtual void RequestMountInfoRefresh() OVERRIDE {} |
| 131 virtual bool IsBootPath(const char* device_path) { return true; } | 347 virtual void MountPath(const char* device_path) OVERRIDE {} |
| 348 virtual void UnmountPath(const char* device_path) OVERRIDE {} | |
| 349 virtual bool IsBootPath(const char* device_path) OVERRIDE { return true; } | |
| 132 | 350 |
| 133 private: | 351 private: |
| 134 // The list of disks found. | 352 // The list of disks found. |
| 135 DiskVector disks_; | 353 DiskMap disks_; |
| 136 | 354 |
| 137 DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl); | 355 DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl); |
| 138 }; | 356 }; |
| 139 | 357 |
| 140 // static | 358 // static |
| 141 MountLibrary* MountLibrary::GetImpl(bool stub) { | 359 MountLibrary* MountLibrary::GetImpl(bool stub) { |
| 142 if (stub) | 360 if (stub) |
| 143 return new MountLibraryStubImpl(); | 361 return new MountLibraryStubImpl(); |
| 144 else | 362 else |
| 145 return new MountLibraryImpl(); | 363 return new MountLibraryImpl(); |
| 146 } | 364 } |
| 147 | 365 |
| 148 } // namespace chromeos | 366 } // namespace chromeos |
| 149 | 367 |
| 150 // Allows InvokeLater without adding refcounting. This class is a Singleton and | 368 // Allows InvokeLater without adding refcounting. This class is a Singleton and |
| 151 // won't be deleted until it's last InvokeLater is run. | 369 // won't be deleted until it's last InvokeLater is run. |
| 152 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl); | 370 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl); |
| 153 | 371 |
| OLD | NEW |