Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/system_monitor/removable_device_notifications_window_wi n.h" | 5 #include "chrome/browser/system_monitor/removable_device_notifications_window_wi n.h" |
| 6 | 6 |
| 7 #include <dbt.h> | 7 #include <dbt.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/scoped_temp_dir.h" | 15 #include "base/scoped_temp_dir.h" |
| 16 #include "base/system_monitor/system_monitor.h" | 16 #include "base/system_monitor/system_monitor.h" |
| 17 #include "base/test/mock_devices_changed_observer.h" | 17 #include "base/test/mock_devices_changed_observer.h" |
| 18 #include "base/threading/sequenced_worker_pool.h" | |
| 18 #include "chrome/browser/system_monitor/media_storage_util.h" | 19 #include "chrome/browser/system_monitor/media_storage_util.h" |
| 20 #include "chrome/browser/system_monitor/removable_device_constants.h" | |
| 19 #include "chrome/browser/system_monitor/volume_mount_watcher_win.h" | 21 #include "chrome/browser/system_monitor/volume_mount_watcher_win.h" |
| 20 #include "content/public/test/test_browser_thread.h" | 22 #include "content/public/test/test_browser_thread.h" |
| 21 #include "testing/gmock/include/gmock/gmock.h" | 23 #include "testing/gmock/include/gmock/gmock.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
| 23 | 25 |
| 24 namespace { | 26 namespace { |
| 25 | 27 |
| 26 using content::BrowserThread; | 28 using content::BrowserThread; |
| 27 using chrome::RemovableDeviceNotificationsWindowWin; | 29 using chrome::RemovableDeviceNotificationsWindowWin; |
| 28 | 30 |
| 31 // Mtp device interface path constants. | |
| 32 const char16 kMtpDeviceWithInvalidInfo[] = | |
| 33 L"\\?\usb#vid_00&pid_00#0&2&1#{0000-0000-0000-0000-0000})"; | |
| 34 const char16 kMtpDeviceWithValidInfo[] = | |
| 35 L"\\?\usb#vid_ff&pid_000f#32&2&1#{abcd-1234-ffde-1112-9172})"; | |
| 36 const char16 kMtpDeviceWithMultipleStorage[] = | |
| 37 L"\\?\usb#vid_ff&pid_18#32&2&1#{ab33-1de4-f22e-1882-9724})"; | |
| 38 | |
| 39 // Sample mtp device storage information. | |
| 40 const char16 kMtpDeviceFriendlyName[] = L"Camera V1.1"; | |
| 41 const char16 kStorageLabelA[] = L"Camera V1.1 (s10001)"; | |
| 42 const char16 kStorageLabelB[] = L"Camera V1.1 (s20001)"; | |
| 43 const char16 kStorageObjectIdA[] = L"s10001"; | |
| 44 const char16 kStorageObjectIdB[] = L"s20001"; | |
| 45 const char kStorageUniqueIdA[] = | |
| 46 "mtp:StorageSerial:SID-{s10001, D, 12378}:123123"; | |
| 47 const char kStorageUniqueIdB[] = | |
| 48 "mtp:StorageSerial:SID-{s20001, S, 2238}:123123"; | |
| 49 | |
| 29 // Inputs of 'A:\' - 'Z:\' are valid. 'N:\' is not removable. | 50 // Inputs of 'A:\' - 'Z:\' are valid. 'N:\' is not removable. |
| 30 bool GetDeviceDetails(const FilePath& device_path, string16* device_location, | 51 bool GetMassStorageDeviceDetails(const FilePath& device_path, |
| 31 std::string* unique_id, string16* name, bool* removable) { | 52 string16* device_location, std::string* unique_id, string16* name, |
| 53 bool* removable) { | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: One arg per line, indented even (several plac
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 32 if (device_path.value().length() != 3 || device_path.value()[0] < L'A' || | 54 if (device_path.value().length() != 3 || device_path.value()[0] < L'A' || |
| 33 device_path.value()[0] > L'Z') { | 55 device_path.value()[0] > L'Z') { |
| 34 return false; | 56 return false; |
| 35 } | 57 } |
| 36 | 58 |
| 37 if (device_location) | 59 if (device_location) |
| 38 *device_location = device_path.value(); | 60 *device_location = device_path.value(); |
| 39 if (unique_id) { | 61 if (unique_id) { |
| 40 *unique_id = "\\\\?\\Volume{00000000-0000-0000-0000-000000000000}\\"; | 62 *unique_id = "\\\\?\\Volume{00000000-0000-0000-0000-000000000000}\\"; |
| 41 (*unique_id)[11] = device_path.value()[0]; | 63 (*unique_id)[11] = device_path.value()[0]; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 58 result.push_back(DriveNumberToFilePath(0)); | 80 result.push_back(DriveNumberToFilePath(0)); |
| 59 result.push_back(DriveNumberToFilePath(1)); | 81 result.push_back(DriveNumberToFilePath(1)); |
| 60 result.push_back(DriveNumberToFilePath(2)); | 82 result.push_back(DriveNumberToFilePath(2)); |
| 61 result.push_back(DriveNumberToFilePath(3)); | 83 result.push_back(DriveNumberToFilePath(3)); |
| 62 result.push_back(DriveNumberToFilePath(5)); | 84 result.push_back(DriveNumberToFilePath(5)); |
| 63 result.push_back(DriveNumberToFilePath(7)); | 85 result.push_back(DriveNumberToFilePath(7)); |
| 64 result.push_back(DriveNumberToFilePath(25)); | 86 result.push_back(DriveNumberToFilePath(25)); |
| 65 return result; | 87 return result; |
| 66 } | 88 } |
| 67 | 89 |
| 90 // Returns the persistent storage unique id of the device specified by the | |
| 91 // |pnp_device_id|. |storage_object_id| specifies the temporary object | |
| 92 // identifier that uniquely identifies the object on the device. | |
| 93 std::string GetMtpStorageUniqueId(const string16& pnp_device_id, | |
| 94 const string16& storage_object_id) { | |
| 95 if (pnp_device_id == string16(kMtpDeviceWithInvalidInfo)) | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: No need for explicit string16 construction (m
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 96 return std::string(); | |
| 97 | |
| 98 if (storage_object_id == string16(kStorageObjectIdA)) | |
| 99 return kStorageUniqueIdA; | |
| 100 | |
| 101 if (storage_object_id == string16(kStorageObjectIdB)) | |
| 102 return kStorageUniqueIdB; | |
| 103 return std::string(); | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: Or just:
return (storage_object_id == kSto
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 104 } | |
| 105 | |
| 106 // Returns the storage name of the device specified by |pnp_device_id|. | |
| 107 // |storage_object_id| specifies the temporary object identifier that | |
| 108 // uniquely identifies the object on the device. | |
| 109 string16 GetMtpStorageName(const string16& pnp_device_id, | |
| 110 const string16& storage_object_id) { | |
| 111 if (pnp_device_id == string16(kMtpDeviceWithInvalidInfo)) | |
| 112 return string16(); | |
| 113 | |
| 114 if (storage_object_id == string16(kStorageObjectIdA)) | |
| 115 return string16(kStorageLabelA); | |
| 116 | |
| 117 if (storage_object_id == string16(kStorageObjectIdB)) | |
| 118 return string16(kStorageLabelB); | |
| 119 return string16(); | |
| 120 } | |
| 121 | |
| 122 // Returns a list of storage object identifiers of the device given a | |
| 123 // |pnp_device_id|. | |
| 124 std::vector<string16> GetMtpStorageObjectId(const string16& pnp_device_id) { | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: GetMtpStorageObjectIds?
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 125 if (pnp_device_id == string16(kMtpDeviceWithInvalidInfo)) | |
| 126 return std::vector<string16>(); | |
| 127 | |
| 128 std::vector<string16> storage_object_ids; | |
| 129 storage_object_ids.push_back(string16(kStorageObjectIdA)); | |
| 130 | |
| 131 if (pnp_device_id == string16(kMtpDeviceWithMultipleStorage)) | |
| 132 storage_object_ids.push_back(string16(kStorageObjectIdB)); | |
| 133 return storage_object_ids; | |
| 134 } | |
| 135 | |
| 136 // Gets the mtp device storage details given a |pnp_device_id| and | |
| 137 // |storage_object_id|. On success, returns true and fills in | |
| 138 // |device_location|, |unique_id| and |name|. | |
| 139 bool GetMtpStorageDetails( | |
|
Peter Kasting
2012/10/19 21:31:12
This method can't fail, so return void.
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 140 const string16& pnp_device_id, const string16& storage_object_id, | |
| 141 string16* device_location, std::string* unique_id, string16* name) { | |
| 142 if (device_location) | |
| 143 *device_location = pnp_device_id; | |
| 144 | |
| 145 if (unique_id) | |
| 146 *unique_id = GetMtpStorageUniqueId(pnp_device_id, storage_object_id); | |
| 147 | |
| 148 if (name) | |
| 149 *name = GetMtpStorageName(pnp_device_id, storage_object_id); | |
| 150 return true; | |
| 151 } | |
| 152 | |
| 68 } // namespace | 153 } // namespace |
| 69 | 154 |
| 70 namespace chrome { | 155 namespace chrome { |
| 71 | 156 |
| 157 // Wrapper class for testing PortableDeviceWatcherWin. | |
| 158 class TestPortableDeviceWatcherWin : public PortableDeviceWatcherWin { | |
| 159 public: | |
| 160 TestPortableDeviceWatcherWin() { | |
| 161 } | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: Do not define functions inline in class decla
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 162 | |
| 163 private: | |
| 164 // Avoids code deleting the object while there are references to it. | |
| 165 // Aside from the base::RefCountedThreadSafe friend class, any attempts to | |
| 166 // call this dtor will result in a compile-time error. | |
| 167 virtual ~TestPortableDeviceWatcherWin() { | |
| 168 } | |
| 169 | |
| 170 // Override PortableDeviceWatcherWin::InitOnBlockingThread. | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: Don't comment individual function overrides t
kmadhusu
2012/10/23 23:44:17
Done.
| |
| 171 void InitOnBlockingThread() OVERRIDE { | |
| 172 } | |
| 173 | |
| 174 // Override PortableDeviceWatcherWin::GetDeviceName. | |
| 175 virtual string16 GetDeviceName(const string16& pnp_device_id) OVERRIDE { | |
| 176 if (pnp_device_id == string16(kMtpDeviceWithInvalidInfo)) | |
| 177 return string16(); | |
| 178 return string16(kMtpDeviceFriendlyName); | |
| 179 } | |
| 180 | |
| 181 // Override PortableDeviceWatcherWin::GetStorages. | |
| 182 virtual bool GetStorages(const string16& pnp_device_id, | |
| 183 std::vector<DeviceStorageInfo>* storages) OVERRIDE { | |
| 184 if (pnp_device_id == string16(kMtpDeviceWithInvalidInfo)) | |
| 185 return false; | |
| 186 | |
| 187 std::vector<string16> storage_object_ids = | |
| 188 GetMtpStorageObjectId(pnp_device_id); | |
| 189 for (size_t index = 0; index < storage_object_ids.size(); ++index) { | |
| 190 DeviceStorageInfo storage; | |
| 191 storage.unique_id = GetMtpStorageUniqueId(pnp_device_id, | |
| 192 storage_object_ids[index]); | |
| 193 storage.storage_object_id = storage_object_ids[index]; | |
| 194 storages->push_back(storage); | |
| 195 } | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 DISALLOW_COPY_AND_ASSIGN(TestPortableDeviceWatcherWin); | |
| 200 }; | |
| 201 | |
| 72 // Wrapper class for testing VolumeMountWatcherWin. | 202 // Wrapper class for testing VolumeMountWatcherWin. |
| 73 class TestVolumeMountWatcherWin : public VolumeMountWatcherWin { | 203 class TestVolumeMountWatcherWin : public VolumeMountWatcherWin { |
| 74 public: | 204 public: |
| 75 TestVolumeMountWatcherWin() : pre_attach_devices_(false) { | 205 TestVolumeMountWatcherWin() : pre_attach_devices_(false) { |
| 76 } | 206 } |
| 77 | 207 |
| 78 // Override VolumeMountWatcherWin::GetDeviceInfo(). | 208 // Override VolumeMountWatcherWin::GetDeviceInfo(). |
| 79 virtual bool GetDeviceInfo(const FilePath& device_path, | 209 virtual bool GetDeviceInfo(const FilePath& device_path, |
| 80 string16* device_location, std::string* unique_id, string16* name, | 210 string16* device_location, std::string* unique_id, string16* name, |
| 81 bool* removable) OVERRIDE { | 211 bool* removable) OVERRIDE { |
| 82 return GetDeviceDetails(device_path, device_location, unique_id, name, | 212 return GetMassStorageDeviceDetails(device_path, device_location, unique_id, |
| 83 removable); | 213 name, removable); |
| 84 } | 214 } |
| 85 | 215 |
| 86 // Override VolumeMountWatcherWin::GetAttachedDevices(). | 216 // Override VolumeMountWatcherWin::GetAttachedDevices(). |
| 87 virtual std::vector<FilePath> GetAttachedDevices() OVERRIDE{ | 217 virtual std::vector<FilePath> GetAttachedDevices() OVERRIDE{ |
| 88 if (pre_attach_devices_) | 218 if (pre_attach_devices_) |
| 89 return GetTestAttachedDevices(); | 219 return GetTestAttachedDevices(); |
| 90 return std::vector<FilePath>(); | 220 return std::vector<FilePath>(); |
| 91 } | 221 } |
| 92 | 222 |
| 93 void set_pre_attach_devices(bool pre_attach_devices) { | 223 void set_pre_attach_devices(bool pre_attach_devices) { |
| 94 pre_attach_devices_ = pre_attach_devices; | 224 pre_attach_devices_ = pre_attach_devices; |
| 95 } | 225 } |
| 96 | 226 |
| 97 private: | 227 private: |
| 98 // Private, this class is ref-counted. | 228 // Private, this class is ref-counted. |
| 99 virtual ~TestVolumeMountWatcherWin() { | 229 virtual ~TestVolumeMountWatcherWin() { |
| 100 } | 230 } |
| 101 | 231 |
| 102 // Set to true to pre-attach test devices. | 232 // Set to true to pre-attach test devices. |
| 103 bool pre_attach_devices_; | 233 bool pre_attach_devices_; |
| 104 }; | 234 }; |
| 105 | 235 |
| 106 // Wrapper class for testing RemovableDeviceNotificationsWindowWin. | 236 // Wrapper class for testing RemovableDeviceNotificationsWindowWin. |
| 107 class TestRemovableDeviceNotificationsWindowWin | 237 class TestRemovableDeviceNotificationsWindowWin |
| 108 : public RemovableDeviceNotificationsWindowWin { | 238 : public RemovableDeviceNotificationsWindowWin { |
| 109 public: | 239 public: |
| 110 explicit TestRemovableDeviceNotificationsWindowWin( | 240 explicit TestRemovableDeviceNotificationsWindowWin( |
| 111 TestVolumeMountWatcherWin* volume_mount_watcher) | 241 TestVolumeMountWatcherWin* volume_mount_watcher, |
| 112 : RemovableDeviceNotificationsWindowWin(volume_mount_watcher), | 242 TestPortableDeviceWatcherWin* portable_device_watcher) |
| 243 : RemovableDeviceNotificationsWindowWin( | |
| 244 volume_mount_watcher, portable_device_watcher), | |
| 113 volume_mount_watcher_(volume_mount_watcher) { | 245 volume_mount_watcher_(volume_mount_watcher) { |
| 114 DCHECK(volume_mount_watcher_); | 246 DCHECK(volume_mount_watcher_); |
| 115 } | 247 } |
| 116 | 248 |
| 117 virtual ~TestRemovableDeviceNotificationsWindowWin() { | 249 virtual ~TestRemovableDeviceNotificationsWindowWin() { |
| 118 } | 250 } |
| 119 | 251 |
| 120 void InitWithTestData() { | 252 void InitWithTestData() { |
| 121 volume_mount_watcher_->set_pre_attach_devices(false); | 253 volume_mount_watcher_->set_pre_attach_devices(false); |
| 122 Init(); | 254 Init(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 139 public: | 271 public: |
| 140 RemovableDeviceNotificationsWindowWinTest() | 272 RemovableDeviceNotificationsWindowWinTest() |
| 141 : ui_thread_(BrowserThread::UI, &message_loop_), | 273 : ui_thread_(BrowserThread::UI, &message_loop_), |
| 142 file_thread_(BrowserThread::FILE, &message_loop_) { } | 274 file_thread_(BrowserThread::FILE, &message_loop_) { } |
| 143 virtual ~RemovableDeviceNotificationsWindowWinTest() { } | 275 virtual ~RemovableDeviceNotificationsWindowWinTest() { } |
| 144 | 276 |
| 145 protected: | 277 protected: |
| 146 virtual void SetUp() OVERRIDE { | 278 virtual void SetUp() OVERRIDE { |
| 147 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 279 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 148 volume_mount_watcher_ = new TestVolumeMountWatcherWin; | 280 volume_mount_watcher_ = new TestVolumeMountWatcherWin; |
| 281 portable_device_watcher_ = new TestPortableDeviceWatcherWin; | |
| 149 window_.reset(new TestRemovableDeviceNotificationsWindowWin( | 282 window_.reset(new TestRemovableDeviceNotificationsWindowWin( |
| 150 volume_mount_watcher_.get())); | 283 volume_mount_watcher_.get(), portable_device_watcher_.get())); |
| 151 window_->InitWithTestData(); | 284 window_->InitWithTestData(); |
| 152 message_loop_.RunAllPending(); | 285 RunAllPending(); |
| 153 system_monitor_.AddDevicesChangedObserver(&observer_); | 286 system_monitor_.AddDevicesChangedObserver(&observer_); |
| 154 } | 287 } |
| 155 | 288 |
| 156 virtual void TearDown() { | 289 virtual void TearDown() { |
| 157 message_loop_.RunAllPending(); | 290 RunAllPending(); |
| 158 system_monitor_.RemoveDevicesChangedObserver(&observer_); | 291 system_monitor_.RemoveDevicesChangedObserver(&observer_); |
| 159 } | 292 } |
| 160 | 293 |
| 161 void AddAttachExpectation(FilePath drive) { | 294 void AddAttachExpectation(FilePath drive) { |
| 162 std::string unique_id; | 295 std::string unique_id; |
| 163 string16 device_name; | 296 string16 device_name; |
| 164 bool removable; | 297 bool removable; |
| 165 ASSERT_TRUE(GetDeviceDetails(drive, NULL, &unique_id, &device_name, | 298 ASSERT_TRUE(GetMassStorageDeviceDetails(drive, NULL, &unique_id, |
| 166 &removable)); | 299 &device_name, &removable)); |
| 167 if (removable) { | 300 if (removable) { |
| 168 MediaStorageUtil::Type type = | 301 MediaStorageUtil::Type type = |
| 169 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; | 302 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; |
| 170 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); | 303 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); |
| 171 EXPECT_CALL(observer_, OnRemovableStorageAttached(device_id, device_name, | 304 EXPECT_CALL(observer_, OnRemovableStorageAttached(device_id, device_name, |
| 172 drive.value())) | 305 drive.value())) |
| 173 .Times(1); | 306 .Times(1); |
| 174 } | 307 } |
| 175 } | 308 } |
| 176 | 309 |
| 177 void PreAttachDevices() { | 310 void PreAttachDevices() { |
| 178 window_.reset(); | 311 window_.reset(); |
| 179 { | 312 { |
| 180 testing::InSequence sequence; | 313 testing::InSequence sequence; |
| 181 std::vector<FilePath> initial_devices = GetTestAttachedDevices(); | 314 std::vector<FilePath> initial_devices = GetTestAttachedDevices(); |
| 182 for (size_t i = 0; i < initial_devices.size(); i++) | 315 for (size_t i = 0; i < initial_devices.size(); i++) |
| 183 AddAttachExpectation(initial_devices[i]); | 316 AddAttachExpectation(initial_devices[i]); |
| 184 } | 317 } |
| 185 window_.reset(new TestRemovableDeviceNotificationsWindowWin( | 318 window_.reset(new TestRemovableDeviceNotificationsWindowWin( |
| 186 volume_mount_watcher_.get())); | 319 volume_mount_watcher_.get(), portable_device_watcher_.get())); |
| 187 window_->InitWithTestDataAndAttachedDevices(); | 320 window_->InitWithTestDataAndAttachedDevices(); |
| 321 RunAllPending(); | |
| 322 } | |
| 323 | |
| 324 // Runs all the pending tasks on UI thread and blocking thread. | |
| 325 void RunAllPending() { | |
| 326 message_loop_.RunAllPending(); | |
| 327 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 188 message_loop_.RunAllPending(); | 328 message_loop_.RunAllPending(); |
| 189 } | 329 } |
| 190 | 330 |
| 191 void DoDevicesAttachedTest(const std::vector<int>& device_indices); | 331 void DoMassStorageDeviceAttachedTest(const std::vector<int>& device_indices); |
| 192 void DoDevicesDetachedTest(const std::vector<int>& device_indices); | 332 void DoMassStorageDevicesDetachedTest(const std::vector<int>& device_indices); |
| 333 void DoMtpDeviceAttachedTest(const string16& pnp_device_id); | |
| 334 void DoMtpDeviceDetachedTest(const string16& pnp_device_id); | |
| 193 | 335 |
| 194 MessageLoopForUI message_loop_; | 336 MessageLoopForUI message_loop_; |
| 195 content::TestBrowserThread ui_thread_; | 337 content::TestBrowserThread ui_thread_; |
| 196 content::TestBrowserThread file_thread_; | 338 content::TestBrowserThread file_thread_; |
| 197 | 339 |
| 198 base::SystemMonitor system_monitor_; | 340 base::SystemMonitor system_monitor_; |
| 199 base::MockDevicesChangedObserver observer_; | 341 base::MockDevicesChangedObserver observer_; |
| 200 scoped_ptr<TestRemovableDeviceNotificationsWindowWin> window_; | 342 scoped_ptr<TestRemovableDeviceNotificationsWindowWin> window_; |
| 201 scoped_refptr<TestVolumeMountWatcherWin> volume_mount_watcher_; | 343 scoped_refptr<TestVolumeMountWatcherWin> volume_mount_watcher_; |
| 344 scoped_refptr<TestPortableDeviceWatcherWin> portable_device_watcher_; | |
| 202 }; | 345 }; |
| 203 | 346 |
| 204 void RemovableDeviceNotificationsWindowWinTest::DoDevicesAttachedTest( | 347 void RemovableDeviceNotificationsWindowWinTest:: |
| 348 DoMassStorageDeviceAttachedTest( | |
| 205 const std::vector<int>& device_indices) { | 349 const std::vector<int>& device_indices) { |
| 206 DEV_BROADCAST_VOLUME volume_broadcast; | 350 DEV_BROADCAST_VOLUME volume_broadcast; |
| 207 volume_broadcast.dbcv_size = sizeof(volume_broadcast); | 351 volume_broadcast.dbcv_size = sizeof(volume_broadcast); |
| 208 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; | 352 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; |
| 209 volume_broadcast.dbcv_unitmask = 0x0; | 353 volume_broadcast.dbcv_unitmask = 0x0; |
| 210 volume_broadcast.dbcv_flags = 0x0; | 354 volume_broadcast.dbcv_flags = 0x0; |
| 211 { | 355 { |
| 212 testing::InSequence sequence; | 356 testing::InSequence sequence; |
| 213 for (std::vector<int>::const_iterator it = device_indices.begin(); | 357 for (std::vector<int>::const_iterator it = device_indices.begin(); |
| 214 it != device_indices.end(); | 358 it != device_indices.end(); |
| 215 ++it) { | 359 ++it) { |
| 216 volume_broadcast.dbcv_unitmask |= 0x1 << *it; | 360 volume_broadcast.dbcv_unitmask |= 0x1 << *it; |
| 217 AddAttachExpectation(DriveNumberToFilePath(*it)); | 361 AddAttachExpectation(DriveNumberToFilePath(*it)); |
| 218 } | 362 } |
| 219 } | 363 } |
| 220 window_->InjectDeviceChange(DBT_DEVICEARRIVAL, | 364 window_->InjectDeviceChange(DBT_DEVICEARRIVAL, |
| 221 reinterpret_cast<DWORD>(&volume_broadcast)); | 365 reinterpret_cast<DWORD>(&volume_broadcast)); |
| 222 message_loop_.RunAllPending(); | 366 RunAllPending(); |
| 223 } | 367 } |
| 224 | 368 |
| 225 void RemovableDeviceNotificationsWindowWinTest::DoDevicesDetachedTest( | 369 void RemovableDeviceNotificationsWindowWinTest:: |
| 370 DoMassStorageDevicesDetachedTest( | |
| 226 const std::vector<int>& device_indices) { | 371 const std::vector<int>& device_indices) { |
| 227 DEV_BROADCAST_VOLUME volume_broadcast; | 372 DEV_BROADCAST_VOLUME volume_broadcast; |
| 228 volume_broadcast.dbcv_size = sizeof(volume_broadcast); | 373 volume_broadcast.dbcv_size = sizeof(volume_broadcast); |
| 229 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; | 374 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; |
| 230 volume_broadcast.dbcv_unitmask = 0x0; | 375 volume_broadcast.dbcv_unitmask = 0x0; |
| 231 volume_broadcast.dbcv_flags = 0x0; | 376 volume_broadcast.dbcv_flags = 0x0; |
| 232 { | 377 { |
| 233 testing::InSequence sequence; | 378 testing::InSequence sequence; |
| 234 for (std::vector<int>::const_iterator it = device_indices.begin(); | 379 for (std::vector<int>::const_iterator it = device_indices.begin(); |
| 235 it != device_indices.end(); | 380 it != device_indices.end(); |
| 236 ++it) { | 381 ++it) { |
| 237 volume_broadcast.dbcv_unitmask |= 0x1 << *it; | 382 volume_broadcast.dbcv_unitmask |= 0x1 << *it; |
| 238 std::string unique_id; | 383 std::string unique_id; |
| 239 bool removable; | 384 bool removable; |
| 240 ASSERT_TRUE(GetDeviceDetails(DriveNumberToFilePath(*it), NULL, &unique_id, | 385 ASSERT_TRUE(GetMassStorageDeviceDetails(DriveNumberToFilePath(*it), NULL, |
| 241 NULL, &removable)); | 386 &unique_id, NULL, &removable)); |
| 242 if (removable) { | 387 if (removable) { |
| 243 MediaStorageUtil::Type type = | 388 MediaStorageUtil::Type type = |
| 244 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; | 389 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; |
| 245 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); | 390 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); |
| 246 EXPECT_CALL(observer_, OnRemovableStorageDetached(device_id)).Times(1); | 391 EXPECT_CALL(observer_, OnRemovableStorageDetached(device_id)).Times(1); |
| 247 } | 392 } |
| 248 } | 393 } |
| 249 } | 394 } |
| 250 window_->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE, | 395 window_->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE, |
| 251 reinterpret_cast<DWORD>(&volume_broadcast)); | 396 reinterpret_cast<DWORD>(&volume_broadcast)); |
| 252 message_loop_.RunAllPending(); | 397 RunAllPending(); |
| 398 } | |
| 399 | |
| 400 void RemovableDeviceNotificationsWindowWinTest::DoMtpDeviceAttachedTest( | |
| 401 const string16& pnp_device_id) { | |
| 402 GUID guidDevInterface = GUID_NULL; | |
| 403 HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface); | |
| 404 if (FAILED(hr)) | |
| 405 return; | |
| 406 | |
| 407 size_t device_id_size = pnp_device_id.size() * sizeof(char16); | |
| 408 size_t dbcc_name_size = device_id_size + sizeof(char16); | |
|
Peter Kasting
2012/10/19 21:31:12
Nit: Inline into next statement (2 places)
kmadhusu
2012/10/23 23:44:17
I would like to leave this as it is. To me, this i
Peter Kasting
2012/10/24 00:06:32
Actually, now that I look closer, this statement i
| |
| 409 size_t size = sizeof(DEV_BROADCAST_DEVICEINTERFACE) + dbcc_name_size; | |
| 410 scoped_ptr_malloc<DEV_BROADCAST_DEVICEINTERFACE> dev_interface_broadcast( | |
|
Peter Kasting
2012/10/19 21:31:12
Ugh, why are you using scoped_ptr_malloc<> and Zer
kmadhusu
2012/10/23 23:44:17
By default, DEV_BROADCAST_DEVICEINTERFACE dbcc_nam
Peter Kasting
2012/10/24 00:06:32
Yeah, you're fine. I didn't really realize this s
| |
| 411 static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size))); | |
| 412 DCHECK(dev_interface_broadcast.get()); | |
| 413 ZeroMemory(dev_interface_broadcast.get(), size); | |
| 414 dev_interface_broadcast->dbcc_size = size; | |
| 415 dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; | |
| 416 dev_interface_broadcast->dbcc_classguid = guidDevInterface; | |
| 417 memcpy(dev_interface_broadcast->dbcc_name, pnp_device_id.data(), | |
| 418 device_id_size); | |
| 419 { | |
| 420 testing::InSequence sequence; | |
| 421 std::vector<string16> storages = GetMtpStorageObjectId(pnp_device_id); | |
| 422 for (size_t index = 0; index < storages.size(); ++index) { | |
| 423 std::string unique_id; | |
| 424 string16 name; | |
| 425 string16 location; | |
| 426 ASSERT_TRUE(GetMtpStorageDetails(pnp_device_id, storages[index], | |
| 427 &location, &unique_id, &name)); | |
| 428 int cardinality = 1; | |
| 429 if (name.empty() || unique_id.empty()) | |
| 430 cardinality = 0; | |
| 431 EXPECT_CALL(observer_, OnRemovableStorageAttached(unique_id, name, | |
| 432 location)) | |
| 433 .Times(cardinality); | |
| 434 } | |
| 435 } | |
| 436 window_->InjectDeviceChange( | |
| 437 DBT_DEVICEARRIVAL, | |
| 438 reinterpret_cast<DWORD>(dev_interface_broadcast.get())); | |
| 439 RunAllPending(); | |
| 440 } | |
| 441 | |
| 442 void RemovableDeviceNotificationsWindowWinTest::DoMtpDeviceDetachedTest( | |
| 443 const string16& pnp_device_id) { | |
| 444 GUID guidDevInterface = GUID_NULL; | |
| 445 HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface); | |
| 446 if (FAILED(hr)) | |
| 447 return; | |
| 448 | |
| 449 size_t device_id_size = pnp_device_id.size() * sizeof(char16); | |
| 450 size_t dbcc_name_size = device_id_size + sizeof(char16); | |
| 451 size_t size = sizeof(DEV_BROADCAST_DEVICEINTERFACE) + dbcc_name_size; | |
| 452 scoped_ptr_malloc<DEV_BROADCAST_DEVICEINTERFACE> dev_interface_broadcast( | |
| 453 static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size))); | |
| 454 DCHECK(dev_interface_broadcast.get()); | |
| 455 ZeroMemory(dev_interface_broadcast.get(), size); | |
| 456 dev_interface_broadcast->dbcc_size = size; | |
| 457 dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; | |
| 458 dev_interface_broadcast->dbcc_classguid = guidDevInterface; | |
| 459 memcpy(dev_interface_broadcast->dbcc_name, pnp_device_id.data(), | |
| 460 device_id_size); | |
| 461 { | |
| 462 testing::InSequence sequence; | |
| 463 std::vector<string16> storages = GetMtpStorageObjectId(pnp_device_id); | |
| 464 for (size_t index = 0; index < storages.size(); ++index) { | |
| 465 std::string unique_id; | |
| 466 string16 name; | |
| 467 ASSERT_TRUE(GetMtpStorageDetails(pnp_device_id, storages[index], NULL, | |
| 468 &unique_id, &name)); | |
| 469 int cardinality = 1; | |
| 470 if (name.empty() || unique_id.empty()) | |
| 471 cardinality = 0; | |
| 472 EXPECT_CALL(observer_, OnRemovableStorageDetached(unique_id)) | |
| 473 .Times(cardinality); | |
| 474 } | |
| 475 } | |
| 476 window_->InjectDeviceChange( | |
| 477 DBT_DEVICEREMOVECOMPLETE, | |
| 478 reinterpret_cast<DWORD>(dev_interface_broadcast.get())); | |
| 479 RunAllPending(); | |
| 253 } | 480 } |
| 254 | 481 |
| 255 TEST_F(RemovableDeviceNotificationsWindowWinTest, RandomMessage) { | 482 TEST_F(RemovableDeviceNotificationsWindowWinTest, RandomMessage) { |
| 256 window_->InjectDeviceChange(DBT_DEVICEQUERYREMOVE, NULL); | 483 window_->InjectDeviceChange(DBT_DEVICEQUERYREMOVE, NULL); |
| 257 message_loop_.RunAllPending(); | 484 RunAllPending(); |
| 258 } | 485 } |
| 259 | 486 |
| 260 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttached) { | 487 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttached) { |
| 261 std::vector<int> device_indices; | 488 std::vector<int> device_indices; |
| 262 device_indices.push_back(1); | 489 device_indices.push_back(1); |
| 263 device_indices.push_back(5); | 490 device_indices.push_back(5); |
| 264 device_indices.push_back(7); | 491 device_indices.push_back(7); |
| 265 device_indices.push_back(13); | 492 device_indices.push_back(13); |
| 266 | 493 |
| 267 DoDevicesAttachedTest(device_indices); | 494 DoMassStorageDeviceAttachedTest(device_indices); |
| 268 } | 495 } |
| 269 | 496 |
| 270 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedHighBoundary) { | 497 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedHighBoundary) { |
| 271 std::vector<int> device_indices; | 498 std::vector<int> device_indices; |
| 272 device_indices.push_back(25); | 499 device_indices.push_back(25); |
| 273 | 500 |
| 274 DoDevicesAttachedTest(device_indices); | 501 DoMassStorageDeviceAttachedTest(device_indices); |
| 275 } | 502 } |
| 276 | 503 |
| 277 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedLowBoundary) { | 504 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedLowBoundary) { |
| 278 std::vector<int> device_indices; | 505 std::vector<int> device_indices; |
| 279 device_indices.push_back(0); | 506 device_indices.push_back(0); |
| 280 | 507 |
| 281 DoDevicesAttachedTest(device_indices); | 508 DoMassStorageDeviceAttachedTest(device_indices); |
| 282 } | 509 } |
| 283 | 510 |
| 284 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedAdjacentBits) { | 511 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedAdjacentBits) { |
| 285 std::vector<int> device_indices; | 512 std::vector<int> device_indices; |
| 286 device_indices.push_back(0); | 513 device_indices.push_back(0); |
| 287 device_indices.push_back(1); | 514 device_indices.push_back(1); |
| 288 device_indices.push_back(2); | 515 device_indices.push_back(2); |
| 289 device_indices.push_back(3); | 516 device_indices.push_back(3); |
| 290 | 517 |
| 291 DoDevicesAttachedTest(device_indices); | 518 DoMassStorageDeviceAttachedTest(device_indices); |
| 292 } | 519 } |
| 293 | 520 |
| 294 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetached) { | 521 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetached) { |
| 295 PreAttachDevices(); | 522 PreAttachDevices(); |
| 296 | 523 |
| 297 std::vector<int> device_indices; | 524 std::vector<int> device_indices; |
| 298 device_indices.push_back(1); | 525 device_indices.push_back(1); |
| 299 device_indices.push_back(5); | 526 device_indices.push_back(5); |
| 300 device_indices.push_back(7); | 527 device_indices.push_back(7); |
| 301 device_indices.push_back(13); | 528 device_indices.push_back(13); |
| 302 | 529 |
| 303 DoDevicesDetachedTest(device_indices); | 530 DoMassStorageDevicesDetachedTest(device_indices); |
| 304 } | 531 } |
| 305 | 532 |
| 306 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedHighBoundary) { | 533 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedHighBoundary) { |
| 307 PreAttachDevices(); | 534 PreAttachDevices(); |
| 308 | 535 |
| 309 std::vector<int> device_indices; | 536 std::vector<int> device_indices; |
| 310 device_indices.push_back(25); | 537 device_indices.push_back(25); |
| 311 | 538 |
| 312 DoDevicesDetachedTest(device_indices); | 539 DoMassStorageDevicesDetachedTest(device_indices); |
| 313 } | 540 } |
| 314 | 541 |
| 315 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedLowBoundary) { | 542 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedLowBoundary) { |
| 316 PreAttachDevices(); | 543 PreAttachDevices(); |
| 317 | 544 |
| 318 std::vector<int> device_indices; | 545 std::vector<int> device_indices; |
| 319 device_indices.push_back(0); | 546 device_indices.push_back(0); |
| 320 | 547 |
| 321 DoDevicesDetachedTest(device_indices); | 548 DoMassStorageDevicesDetachedTest(device_indices); |
| 322 } | 549 } |
| 323 | 550 |
| 324 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedAdjacentBits) { | 551 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedAdjacentBits) { |
| 325 PreAttachDevices(); | 552 PreAttachDevices(); |
| 326 | 553 |
| 327 std::vector<int> device_indices; | 554 std::vector<int> device_indices; |
| 328 device_indices.push_back(0); | 555 device_indices.push_back(0); |
| 329 device_indices.push_back(1); | 556 device_indices.push_back(1); |
| 330 device_indices.push_back(2); | 557 device_indices.push_back(2); |
| 331 device_indices.push_back(3); | 558 device_indices.push_back(3); |
| 332 | 559 |
| 333 DoDevicesDetachedTest(device_indices); | 560 DoMassStorageDevicesDetachedTest(device_indices); |
| 334 } | 561 } |
| 335 | 562 |
| 336 TEST_F(RemovableDeviceNotificationsWindowWinTest, DeviceInfoFoPath) { | 563 TEST_F(RemovableDeviceNotificationsWindowWinTest, DeviceInfoFoPath) { |
| 337 PreAttachDevices(); | 564 PreAttachDevices(); |
| 338 | 565 |
| 339 // An invalid path. | 566 // An invalid path. |
| 340 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"COM1:\\"), NULL)); | 567 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"COM1:\\"), NULL)); |
| 341 | 568 |
| 342 // An unconnected removable device. | 569 // An unconnected removable device. |
| 343 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"E:\\"), NULL)); | 570 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"E:\\"), NULL)); |
| 344 | 571 |
| 345 // A connected removable device. | 572 // A connected removable device. |
| 346 FilePath removable_device(L"F:\\"); | 573 FilePath removable_device(L"F:\\"); |
| 347 base::SystemMonitor::RemovableStorageInfo device_info; | 574 base::SystemMonitor::RemovableStorageInfo device_info; |
| 348 EXPECT_TRUE(window_->GetDeviceInfoForPath(removable_device, &device_info)); | 575 EXPECT_TRUE(window_->GetDeviceInfoForPath(removable_device, &device_info)); |
| 349 | 576 |
| 350 std::string unique_id; | 577 std::string unique_id; |
| 351 string16 device_name; | 578 string16 device_name; |
| 352 bool removable; | 579 bool removable; |
| 353 ASSERT_TRUE(GetDeviceDetails(removable_device, NULL, &unique_id, &device_name, | 580 ASSERT_TRUE(GetMassStorageDeviceDetails(removable_device, NULL, &unique_id, |
| 354 &removable)); | 581 &device_name, &removable)); |
| 355 EXPECT_TRUE(removable); | 582 EXPECT_TRUE(removable); |
| 356 std::string device_id = MediaStorageUtil::MakeDeviceId( | 583 std::string device_id = MediaStorageUtil::MakeDeviceId( |
| 357 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM, unique_id); | 584 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM, unique_id); |
| 358 EXPECT_EQ(device_id, device_info.device_id); | 585 EXPECT_EQ(device_id, device_info.device_id); |
| 359 EXPECT_EQ(device_name, device_info.name); | 586 EXPECT_EQ(device_name, device_info.name); |
| 360 EXPECT_EQ(removable_device.value(), device_info.location); | 587 EXPECT_EQ(removable_device.value(), device_info.location); |
| 361 | 588 |
| 362 // A fixed device. | 589 // A fixed device. |
| 363 FilePath fixed_device(L"N:\\"); | 590 FilePath fixed_device(L"N:\\"); |
| 364 EXPECT_TRUE(window_->GetDeviceInfoForPath(fixed_device, &device_info)); | 591 EXPECT_TRUE(window_->GetDeviceInfoForPath(fixed_device, &device_info)); |
| 365 | 592 |
| 366 ASSERT_TRUE(GetDeviceDetails(fixed_device, NULL, &unique_id, &device_name, | 593 ASSERT_TRUE(GetMassStorageDeviceDetails(fixed_device, NULL, &unique_id, |
| 367 &removable)); | 594 &device_name, &removable)); |
| 368 EXPECT_FALSE(removable); | 595 EXPECT_FALSE(removable); |
| 369 device_id = MediaStorageUtil::MakeDeviceId( | 596 device_id = MediaStorageUtil::MakeDeviceId( |
| 370 MediaStorageUtil::FIXED_MASS_STORAGE, unique_id); | 597 MediaStorageUtil::FIXED_MASS_STORAGE, unique_id); |
| 371 EXPECT_EQ(device_id, device_info.device_id); | 598 EXPECT_EQ(device_id, device_info.device_id); |
| 372 EXPECT_EQ(device_name, device_info.name); | 599 EXPECT_EQ(device_name, device_info.name); |
| 373 EXPECT_EQ(fixed_device.value(), device_info.location); | 600 EXPECT_EQ(fixed_device.value(), device_info.location); |
| 374 } | 601 } |
| 375 | 602 |
| 603 // Test to verify basic mtp storage attach and detach notifications. | |
| 604 TEST_F(RemovableDeviceNotificationsWindowWinTest, MtpDeviceBasicAttachDetach) { | |
| 605 // Attach a mtp device. | |
| 606 DoMtpDeviceAttachedTest(kMtpDeviceWithValidInfo); | |
| 607 | |
| 608 // Detach the attached device. | |
| 609 DoMtpDeviceDetachedTest(kMtpDeviceWithValidInfo); | |
| 610 } | |
| 611 | |
| 612 // When a mtp storage device with invalid storage label and id is | |
| 613 // attached/detached, there should not be any device attach/detach | |
| 614 // notifications. | |
| 615 TEST_F(RemovableDeviceNotificationsWindowWinTest, MtpDeviceWithInvalidInfo) { | |
| 616 // Attach the mtp storage with invalid storage info. | |
| 617 DoMtpDeviceAttachedTest(kMtpDeviceWithInvalidInfo); | |
| 618 | |
| 619 // Detach the attached storage. | |
| 620 DoMtpDeviceDetachedTest(kMtpDeviceWithInvalidInfo); | |
| 621 } | |
| 622 | |
| 623 // Attach a device with two data storages. Verify that attach/detach | |
| 624 // notifications are sent out for each removable storage. | |
| 625 TEST_F(RemovableDeviceNotificationsWindowWinTest, | |
| 626 MtpDeviceWithMultipleStorages) { | |
| 627 // Attach the mtp device with multiple storage. | |
| 628 DoMtpDeviceAttachedTest(kMtpDeviceWithMultipleStorage); | |
| 629 | |
| 630 // Detach the attached device. | |
| 631 DoMtpDeviceDetachedTest(kMtpDeviceWithMultipleStorage); | |
| 632 } | |
| 633 | |
| 376 } // namespace chrome | 634 } // namespace chrome |
| OLD | NEW |