OLD | NEW |
---|---|
(Empty) | |
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 "chrome/browser/system_monitor/portable_device_watcher_win.h" | |
6 | |
7 #include <dbt.h> | |
8 #include <portabledevice.h> | |
9 | |
10 #include "base/file_path.h" | |
11 #include "base/logging.h" | |
12 #include "base/stl_util.h" | |
13 #include "base/string_util.h" | |
14 #include "base/threading/sequenced_worker_pool.h" | |
15 #include "base/utf_string_conversions.h" | |
16 #include "base/win/scoped_co_mem.h" | |
17 #include "base/win/scoped_comptr.h" | |
18 #include "chrome/browser/system_monitor/media_storage_util.h" | |
19 #include "chrome/browser/system_monitor/removable_device_constants.h" | |
20 #include "content/public/browser/browser_thread.h" | |
21 | |
22 namespace chrome { | |
23 | |
24 namespace { | |
25 | |
26 // Name of the client application that communicates with the mtp device. | |
27 const char16 kClientName[] = L"Chromium"; | |
28 | |
29 // Name of the sequenced task runner. | |
30 const char kMediaTaskRunnerName[] = "media-task-runner"; | |
31 | |
32 // Returns true if |data| represents a class of portable devices. | |
33 bool IsPortableDeviceStructure(LPARAM data) { | |
34 DEV_BROADCAST_HDR* broadcast_hdr = | |
35 reinterpret_cast<DEV_BROADCAST_HDR*>(data); | |
36 if (!broadcast_hdr || | |
37 (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) { | |
38 return false; | |
39 } | |
40 | |
41 GUID guidDevInterface = GUID_NULL; | |
42 if (FAILED(CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface))) | |
43 return false; | |
44 DEV_BROADCAST_DEVICEINTERFACE* dev_interface = | |
45 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data); | |
46 return (IsEqualGUID(dev_interface->dbcc_classguid, guidDevInterface) != 0); | |
47 } | |
48 | |
49 // Returns the portable device plug and play device ID string. | |
50 string16 GetPnpDeviceId(LPARAM data) { | |
51 DEV_BROADCAST_DEVICEINTERFACE* dev_interface = | |
52 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data); | |
53 if (!dev_interface) | |
54 return string16(); | |
55 string16 device_id(dev_interface->dbcc_name); | |
56 DCHECK(IsStringASCII(device_id)); | |
57 return StringToLowerASCII(device_id); | |
58 } | |
59 | |
60 // Gets the friendly name of the device specified by the |pnp_device_id|. On | |
61 // success, returns true and fills in |name|. | |
62 bool GetFriendlyName(const string16& pnp_device_id, | |
63 IPortableDeviceManager* device_manager, | |
64 string16* name) { | |
65 DCHECK(device_manager); | |
66 DCHECK(name); | |
67 DWORD name_len = 0; | |
68 HRESULT hr = device_manager->GetDeviceFriendlyName(pnp_device_id.c_str(), | |
69 NULL, &name_len); | |
70 if (FAILED(hr)) | |
71 return false; | |
72 | |
73 hr = device_manager->GetDeviceFriendlyName( | |
74 pnp_device_id.c_str(), WriteInto(name, name_len), &name_len); | |
75 return SUCCEEDED(hr) ? !name->empty() : false; | |
Peter Kasting
2012/10/26 23:46:23
Nit: Simpler:
return SUCCEEDED(hr) && !name->em
kmadhusu
2012/10/28 22:57:16
Done.
| |
76 } | |
77 | |
78 // Gets the manufacturer name of the device specified by the |pnp_device_id|. | |
79 // On success, returns true and fills in |name|. | |
80 bool GetManufacturerName(const string16& pnp_device_id, | |
81 IPortableDeviceManager* device_manager, | |
82 string16* name) { | |
83 DCHECK(device_manager); | |
84 DCHECK(name); | |
85 DWORD name_len = 0; | |
86 HRESULT hr = device_manager->GetDeviceManufacturer(pnp_device_id.c_str(), | |
87 NULL, &name_len); | |
88 if (FAILED(hr)) | |
89 return false; | |
90 | |
91 hr = device_manager->GetDeviceManufacturer(pnp_device_id.c_str(), | |
92 WriteInto(name, name_len), | |
93 &name_len); | |
94 return SUCCEEDED(hr) ? !name->empty() : false; | |
95 } | |
96 | |
97 // Gets the description of the device specified by the |pnp_device_id|. On | |
98 // success, returns true and fills in |description|. | |
99 bool GetDeviceDescription(const string16& pnp_device_id, | |
100 IPortableDeviceManager* device_manager, | |
101 string16* description) { | |
102 DCHECK(device_manager); | |
103 DCHECK(description); | |
104 DWORD desc_len = 0; | |
105 HRESULT hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(), NULL, | |
106 &desc_len); | |
107 if (FAILED(hr)) | |
108 return false; | |
109 | |
110 hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(), | |
111 WriteInto(description, desc_len), | |
112 &desc_len); | |
113 return SUCCEEDED(hr) ? !description->empty() : false; | |
114 } | |
115 | |
116 // On success, returns true and updates |client_info| with a reference to an | |
117 // IPortableDeviceValues interface that holds information about the | |
118 // application that communicates with the device. | |
119 bool GetClientInformation( | |
120 base::win::ScopedComPtr<IPortableDeviceValues>* client_info) { | |
121 HRESULT hr = client_info->CreateInstance(__uuidof(PortableDeviceValues), | |
122 NULL, CLSCTX_INPROC_SERVER); | |
123 if (FAILED(hr)) { | |
124 DPLOG(ERROR) << "Failed to create an instance of IPortableDeviceValues"; | |
125 return false; | |
126 } | |
127 | |
128 // Attempt to set client details. | |
129 (*client_info)->SetStringValue(WPD_CLIENT_NAME, kClientName); | |
130 (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, 0); | |
131 (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, 0); | |
132 (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, 0); | |
133 (*client_info)->SetUnsignedIntegerValue( | |
134 WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION); | |
135 (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, | |
136 GENERIC_READ); | |
137 return true; | |
138 } | |
139 | |
140 // Opens the device for communication. |pnp_device_id| specifies the plug and | |
141 // play device ID string. On success, returns true and updates |device| with a | |
142 // reference to the portable device interface. | |
143 bool SetUp(const string16& pnp_device_id, | |
144 base::win::ScopedComPtr<IPortableDevice>* device) { | |
145 base::win::ScopedComPtr<IPortableDeviceValues> client_info; | |
146 if (!GetClientInformation(&client_info)) | |
147 return false; | |
148 | |
149 HRESULT hr = device->CreateInstance(__uuidof(PortableDevice), NULL, | |
150 CLSCTX_INPROC_SERVER); | |
151 if (FAILED(hr)) { | |
152 DPLOG(ERROR) << "Failed to create an instance of IPortableDevice"; | |
153 return false; | |
154 } | |
155 | |
156 hr = (*device)->Open(pnp_device_id.c_str(), client_info.get()); | |
157 if (SUCCEEDED(hr)) | |
158 return true; | |
159 | |
160 if (hr == E_ACCESSDENIED) | |
161 DPLOG(ERROR) << "Access denied to open the device"; | |
162 return false; | |
163 } | |
164 | |
165 // Returns the unique id property key of the object specified by the | |
166 // |object_id|. | |
167 REFPROPERTYKEY GetUniqueIdPropertyKey(const string16& object_id) { | |
168 return (object_id == WPD_DEVICE_OBJECT_ID) ? | |
169 WPD_DEVICE_SERIAL_NUMBER : WPD_OBJECT_PERSISTENT_UNIQUE_ID; | |
170 } | |
171 | |
172 // On success, returns true and populates |properties_to_read| with the | |
173 // property key of the object specified by the |object_id|. | |
174 bool PopulatePropertyKeyCollection( | |
175 const string16& object_id, | |
176 base::win::ScopedComPtr<IPortableDeviceKeyCollection>* properties_to_read) { | |
177 HRESULT hr = properties_to_read->CreateInstance( | |
178 __uuidof(PortableDeviceKeyCollection), NULL, CLSCTX_INPROC_SERVER); | |
179 if (FAILED(hr)) { | |
180 DPLOG(ERROR) << "Failed to create IPortableDeviceKeyCollection instance"; | |
181 return false; | |
182 } | |
183 REFPROPERTYKEY key = GetUniqueIdPropertyKey(object_id); | |
184 hr = (*properties_to_read)->Add(key); | |
185 return SUCCEEDED(hr); | |
186 } | |
187 | |
188 // Wrapper function to get content property string value. | |
189 bool GetStringPropertyValue(IPortableDeviceValues* properties_values, | |
190 REFPROPERTYKEY key, | |
191 string16* value) { | |
192 DCHECK(properties_values); | |
193 DCHECK(value); | |
194 base::win::ScopedCoMem<char16> buffer; | |
195 HRESULT hr = properties_values->GetStringValue(key, &buffer); | |
196 if (FAILED(hr)) | |
197 return false; | |
198 *value = static_cast<const wchar_t*>(buffer); | |
Peter Kasting
2012/10/26 23:46:23
Nit: wchar_t -> char16, since the original type an
kmadhusu
2012/10/28 22:57:16
Done.
| |
199 return true; | |
200 } | |
201 | |
202 // Constructs a unique identifier for the object specified by the |object_id|. | |
203 // On success, returns true and fills in |unique_id|. | |
204 bool GetObjectUniqueId(IPortableDevice* device, | |
205 const string16& object_id, | |
206 string16* unique_id) { | |
207 DCHECK(device); | |
208 DCHECK(unique_id); | |
209 base::win::ScopedComPtr<IPortableDeviceContent> content; | |
210 HRESULT hr = device->Content(content.Receive()); | |
211 if (FAILED(hr)) { | |
212 DPLOG(ERROR) << "Failed to get IPortableDeviceContent interface"; | |
213 return false; | |
214 } | |
215 | |
216 base::win::ScopedComPtr<IPortableDeviceProperties> properties; | |
217 hr = content->Properties(properties.Receive()); | |
218 if (FAILED(hr)) { | |
219 DPLOG(ERROR) << "Failed to get IPortableDeviceProperties interface"; | |
220 return false; | |
221 } | |
222 | |
223 base::win::ScopedComPtr<IPortableDeviceKeyCollection> properties_to_read; | |
224 if (!PopulatePropertyKeyCollection(object_id, &properties_to_read)) | |
225 return false; | |
226 | |
227 base::win::ScopedComPtr<IPortableDeviceValues> properties_values; | |
228 if (FAILED(properties->GetValues(object_id.c_str(), | |
229 properties_to_read.get(), | |
230 properties_values.Receive()))) { | |
231 return false; | |
232 } | |
233 | |
234 REFPROPERTYKEY key = GetUniqueIdPropertyKey(object_id); | |
235 return GetStringPropertyValue(properties_values.get(), key, unique_id); | |
236 } | |
237 | |
238 // Constructs the device storage unique identifier using |device_serial_num| and | |
239 // |storage_id|. On success, returns true and fills in |device_storage_id|. | |
240 bool ConstructDeviceStorageUniqueId(const string16& device_serial_num, | |
241 const string16& storage_id, | |
242 std::string* device_storage_id) { | |
243 if (device_serial_num.empty() && storage_id.empty()) | |
244 return false; | |
245 | |
246 DCHECK(device_storage_id); | |
247 string16 unique_id(storage_id + L':' + device_serial_num); | |
248 | |
249 *device_storage_id = MediaStorageUtil::MakeDeviceId( | |
250 MediaStorageUtil::MTP_OR_PTP, UTF16ToUTF8(unique_id)); | |
251 return true; | |
252 } | |
253 | |
254 // Gets a list of removable storage object identifiers present in |device|. | |
255 // On success, returns true and fills in |storage_ids|. | |
256 bool GetRemovableStorageObjectIds(IPortableDevice* device, | |
257 std::vector<string16>* storage_ids) { | |
258 DCHECK(device); | |
259 DCHECK(storage_ids); | |
260 base::win::ScopedComPtr<IPortableDeviceCapabilities> capabilities; | |
261 HRESULT hr = device->Capabilities(capabilities.Receive()); | |
262 if (FAILED(hr)) { | |
263 DPLOG(ERROR) << "Failed to get IPortableDeviceCapabilities interface"; | |
264 return false; | |
265 } | |
266 | |
267 base::win::ScopedComPtr<IPortableDevicePropVariantCollection> storage_obj_ids; | |
268 hr = capabilities->GetFunctionalObjects(WPD_FUNCTIONAL_CATEGORY_STORAGE, | |
269 storage_obj_ids.Receive()); | |
270 if (FAILED(hr)) { | |
271 DPLOG(ERROR) << "Failed to get IPortableDevicePropVariantCollection"; | |
272 return false; | |
273 } | |
274 | |
275 DWORD num_storage_obj_ids = 0; | |
276 hr = storage_obj_ids->GetCount(&num_storage_obj_ids); | |
277 if (FAILED(hr)) | |
278 return false; | |
279 | |
280 for (DWORD index = 0; index < num_storage_obj_ids; ++index) { | |
281 PROPVARIANT object_id = {0}; | |
282 PropVariantInit(&object_id); | |
283 hr = storage_obj_ids->GetAt(index, &object_id); | |
284 if (SUCCEEDED(hr) && (object_id.pwszVal != NULL) && | |
285 (object_id.vt == VT_LPWSTR)) { | |
286 storage_ids->push_back(object_id.pwszVal); | |
287 } | |
288 PropVariantClear(&object_id); | |
289 } | |
290 return true; | |
291 } | |
292 | |
293 // Returns true if the portable device is mounted on a volume. |device_name| | |
294 // specifies the name of the device. | |
295 bool IsVolumeMountedPortableDevice(const string16& device_name) { | |
296 // If the device is a volume mounted device, |device_name| will be | |
297 // the volume name. | |
298 return (device_name.length() >= 2) && (device_name[1] == L':') && | |
299 ((device_name[0] >= L'A') && (device_name[0] <= L'Z') || | |
Peter Kasting
2012/10/26 23:46:23
Nit: Should be indented 4.
Also, add parens: righ
kmadhusu
2012/10/28 22:57:16
I thought we align the conditions. I am not sure a
Peter Kasting
2012/10/29 20:41:33
Huh, somehow in the "diff against prior CL" view i
| |
300 ((device_name[0] >= L'a') && (device_name[0] <= L'z'))); | |
301 } | |
302 | |
303 // Returns the name of the device specified by |pnp_device_id|. | |
304 // Since this task may take a longer time to complete, this function is | |
305 // accessed via the media task runner. | |
306 string16 GetDeviceNameOnBlockingThread( | |
307 IPortableDeviceManager* portable_device_manager, | |
308 const string16& pnp_device_id) { | |
309 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
310 DCHECK(portable_device_manager); | |
311 string16 name; | |
312 GetFriendlyName(pnp_device_id, portable_device_manager, &name) || | |
313 GetDeviceDescription(pnp_device_id, portable_device_manager, &name) || | |
314 GetManufacturerName(pnp_device_id, portable_device_manager, &name); | |
315 return name; | |
316 } | |
317 | |
318 // Access the device and gets the device storage details. Since this task may | |
319 // take a longer time to complete, this function is accessed via the media task | |
320 // runner. On success, returns true and populates |storage_objects| with device | |
Peter Kasting
2012/10/26 23:46:23
Nit: You added comments to a number of functions s
kmadhusu
2012/10/28 22:57:16
I misunderstood your earlier comment.
How about
Peter Kasting
2012/10/29 20:41:33
I don't want a block of text that's pasted into se
kmadhusu
2012/10/30 01:29:24
Removed the redundant (on why I am running these t
| |
321 // storage details. | |
322 bool GetDeviceStorageObjectsOnBlockingThread( | |
323 const string16& pnp_device_id, | |
324 PortableDeviceWatcherWin::StorageObjects* storage_objects) { | |
325 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
326 DCHECK(storage_objects); | |
327 base::win::ScopedComPtr<IPortableDevice> device; | |
328 if (!SetUp(pnp_device_id, &device)) | |
329 return false; | |
330 | |
331 string16 device_serial_num; | |
332 if (!GetObjectUniqueId(device.get(), WPD_DEVICE_OBJECT_ID, | |
333 &device_serial_num)) { | |
334 return false; | |
335 } | |
336 | |
337 std::vector<string16> storage_obj_ids; | |
338 if (!GetRemovableStorageObjectIds(device.get(), &storage_obj_ids)) | |
339 return false; | |
340 | |
341 for (std::vector<string16>::const_iterator id_iter = storage_obj_ids.begin(); | |
Peter Kasting
2012/10/26 23:46:23
Nit: You are inconsistent across this file about h
kmadhusu
2012/10/28 22:57:16
"i" or "it" does not provide any information about
| |
342 id_iter != storage_obj_ids.end(); ++id_iter) { | |
343 string16 storage_persistent_id; | |
344 if (!GetObjectUniqueId(device.get(), *id_iter, &storage_persistent_id)) | |
345 continue; | |
346 | |
347 std::string device_storage_id; | |
348 if (ConstructDeviceStorageUniqueId(device_serial_num, storage_persistent_id, | |
349 &device_storage_id)) { | |
350 PortableDeviceWatcherWin::DeviceStorageObject storage_object; | |
Peter Kasting
2012/10/26 23:46:23
Nit: Use aggregate initialization form or add a co
kmadhusu
2012/10/28 22:57:16
Added a constructor.
| |
351 storage_object.object_temporary_id = *id_iter; | |
352 storage_object.object_persistent_id = device_storage_id; | |
353 storage_objects->push_back(storage_object); | |
354 } | |
355 } | |
356 return true; | |
357 } | |
358 | |
359 // Access the device and gets the device details (name, storage info, etc.,). | |
Peter Kasting
2012/10/26 23:46:23
Nit: "Access" -> "Accesses", "etc.," -> "etc."
kmadhusu
2012/10/28 22:57:16
Done.
| |
360 // Since this task may take a longer time to complete, this function is | |
361 // accessed via the media task runner. On success returns true and fills in | |
362 // |device_details|. |pnp_device_id| specifies the plug and play device ID | |
363 // string. | |
364 bool GetDeviceInfoOnBlockingThread( | |
365 IPortableDeviceManager* portable_device_manager, | |
366 const string16& pnp_device_id, | |
367 PortableDeviceWatcherWin::DeviceDetails* device_details) { | |
368 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
369 DCHECK(portable_device_manager); | |
370 DCHECK(device_details); | |
371 DCHECK(!pnp_device_id.empty()); | |
372 | |
373 device_details->name = GetDeviceNameOnBlockingThread(portable_device_manager, | |
374 pnp_device_id); | |
375 if (IsVolumeMountedPortableDevice(device_details->name)) | |
376 return false; | |
377 | |
378 device_details->location = pnp_device_id; | |
379 PortableDeviceWatcherWin::StorageObjects storage_objects; | |
380 return GetDeviceStorageObjectsOnBlockingThread( | |
381 pnp_device_id, &device_details->storage_objects); | |
382 } | |
383 | |
384 // Wrapper function to get an instance of portable device manager. This function | |
385 // may take a long time to complete. Therefore, access this function via a media | |
386 // task runner. On success, returns true and fills in |portable_device_mgr|. | |
387 bool GetPortableDeviceManager( | |
388 base::win::ScopedComPtr<IPortableDeviceManager>* portable_device_mgr) { | |
389 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
390 HRESULT hr = portable_device_mgr->CreateInstance( | |
391 __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER); | |
392 if (SUCCEEDED(hr)) | |
393 return true; | |
394 | |
395 // Either there is no portable device support (it must be a XP with Windows | |
Peter Kasting
2012/10/26 23:46:23
Nit: "it must be a XP with Windows Media Player Ve
kmadhusu
2012/10/28 22:57:16
Done.
| |
396 // Media Player Version < 10) or the thread does not have COM initialized. | |
397 DCHECK_NE(CO_E_NOTINITIALIZED, hr); | |
398 return false; | |
399 } | |
400 | |
401 // Enumerates the attached portable devices. This function accesses the device | |
402 // to get the device details. Since this task may take a longer time to | |
403 // complete, this function is accessed via the media task runner. On success, | |
404 // fills in |device_details_vector| with the attached portable device details. | |
405 void EnumerateAttachedDevicesOnBlockingThread( | |
406 PortableDeviceWatcherWin::DeviceDetailsVector* device_details_vector) { | |
407 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
408 DCHECK(device_details_vector); | |
409 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; | |
410 if (!GetPortableDeviceManager(&portable_device_mgr)) | |
411 return; | |
412 | |
413 // Get the total number of devices found on the system. | |
414 DWORD pnp_device_count = 0; | |
415 HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count); | |
416 if (FAILED(hr)) | |
417 return; | |
418 | |
419 scoped_array<char16*> pnp_device_ids(new char16*[pnp_device_count]); | |
420 ZeroMemory(pnp_device_ids.get(), pnp_device_count); | |
421 hr = portable_device_mgr->GetDevices(pnp_device_ids.get(), &pnp_device_count); | |
422 if (FAILED(hr)) | |
423 return; | |
424 | |
425 for (DWORD index = 0; index < pnp_device_count; ++index) { | |
426 PortableDeviceWatcherWin::DeviceDetails device_details; | |
427 if (!GetDeviceInfoOnBlockingThread(portable_device_mgr, | |
428 pnp_device_ids[index], | |
429 &device_details)) { | |
430 continue; | |
431 } | |
432 device_details_vector->push_back(device_details); | |
433 } | |
434 } | |
435 | |
436 // Handles the device attach event message on a media task runner. This | |
437 // function communicates with the device to get the storage details. This task | |
438 // may take a longer time. Therefore, access this function on a media task | |
439 // runner. |pnp_device_id| specifies the attached plug and play device ID | |
440 // string. On success, populates |device_details| with device information. | |
441 void HandleDeviceAttachedEventOnBlockingThread( | |
442 const string16& pnp_device_id, | |
443 PortableDeviceWatcherWin::DeviceDetails* device_details) { | |
444 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
445 DCHECK(device_details); | |
446 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; | |
447 if (!GetPortableDeviceManager(&portable_device_mgr)) | |
448 return; | |
449 // Sometimes, portable device manager doesn't have the new device details. | |
450 // Refresh the manager device list to update its details. | |
451 portable_device_mgr->RefreshDeviceList(); | |
452 GetDeviceInfoOnBlockingThread(portable_device_mgr, pnp_device_id, | |
453 device_details); | |
454 } | |
455 | |
456 // Constructs and returns a storage path from storage unique identifier. | |
457 string16 GetStoragePathFromStorageId(const std::string& storage_unique_id) { | |
458 // Construct a dummy device path using the storage name. This is only used | |
459 // for registering the device media file system. | |
460 DCHECK(!storage_unique_id.empty()); | |
461 const std::string root_path("\\\\"); | |
Peter Kasting
2012/10/26 23:46:23
Nit: Frankly I think this should just be inlined i
kmadhusu
2012/10/28 22:57:16
Done.
| |
462 return UTF8ToUTF16(root_path + storage_unique_id); | |
463 } | |
464 | |
465 } // namespace | |
466 | |
467 | |
468 /////////////////////////////////////////////////////////////////////////////// | |
469 // PortableDeviceWatcherWin implementation // | |
470 /////////////////////////////////////////////////////////////////////////////// | |
Peter Kasting
2012/10/26 23:46:23
Nit: More common is the following:
...
} // name
kmadhusu
2012/10/28 22:57:16
Done.
| |
471 PortableDeviceWatcherWin::PortableDeviceWatcherWin() | |
472 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
473 } | |
474 | |
475 PortableDeviceWatcherWin::~PortableDeviceWatcherWin() { | |
476 } | |
477 | |
478 void PortableDeviceWatcherWin::Init() { | |
479 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
480 | |
481 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); | |
482 base::SequencedWorkerPool::SequenceToken media_sequence_token = | |
483 pool->GetNamedSequenceToken(kMediaTaskRunnerName); | |
484 media_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior( | |
485 media_sequence_token, base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | |
486 EnumerateAttachedDevices(); | |
487 } | |
488 | |
489 void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { | |
490 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
491 | |
492 if (!IsPortableDeviceStructure(data)) | |
493 return; | |
494 | |
495 string16 device_id = GetPnpDeviceId(data); | |
496 if (event_type == DBT_DEVICEARRIVAL) | |
497 HandleDeviceAttachEvent(device_id); | |
498 else if (event_type == DBT_DEVICEREMOVECOMPLETE) | |
499 HandleDeviceDetachEvent(device_id); | |
500 } | |
501 | |
502 void PortableDeviceWatcherWin::EnumerateAttachedDevices() { | |
503 DCHECK(media_task_runner_.get()); | |
504 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
505 | |
506 DeviceDetailsVector* device_details_vector = new DeviceDetailsVector; | |
507 media_task_runner_->PostTaskAndReply( | |
508 FROM_HERE, | |
509 base::Bind(&EnumerateAttachedDevicesOnBlockingThread, | |
510 device_details_vector), | |
511 base::Bind(&PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices, | |
512 weak_ptr_factory_.GetWeakPtr(), | |
513 base::Owned(device_details_vector))); | |
514 } | |
515 | |
516 void PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices( | |
517 const DeviceDetailsVector* device_details_vector) { | |
518 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
519 DCHECK(device_details_vector); | |
520 for (DeviceDetailsVector::const_iterator it = device_details_vector->begin(); | |
521 it != device_details_vector->end(); ++it) { | |
Peter Kasting
2012/10/26 23:46:23
Nit: {} unnecessary
kmadhusu
2012/10/28 22:57:16
If the condition spans over a line, I am adding {}
| |
522 OnDidHandleDeviceAttachEvent(&(*it)); | |
523 } | |
524 } | |
525 | |
526 void PortableDeviceWatcherWin::HandleDeviceAttachEvent( | |
527 const string16& pnp_device_id) { | |
528 DCHECK(media_task_runner_.get()); | |
529 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
530 | |
531 DeviceDetails* device_details = new DeviceDetails; | |
532 media_task_runner_->PostTaskAndReply( | |
533 FROM_HERE, | |
534 base::Bind(&HandleDeviceAttachedEventOnBlockingThread, pnp_device_id, | |
535 device_details), | |
536 base::Bind(&PortableDeviceWatcherWin::OnDidHandleDeviceAttachEvent, | |
537 weak_ptr_factory_.GetWeakPtr(), | |
538 base::Owned(device_details))); | |
539 } | |
540 | |
541 void PortableDeviceWatcherWin::OnDidHandleDeviceAttachEvent( | |
542 const DeviceDetails* device_details) { | |
543 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
544 DCHECK(device_details); | |
545 | |
Peter Kasting
2012/10/26 23:46:23
HandleDeviceAttachedEvent() can fail and leave |de
kmadhusu
2012/10/28 22:57:16
Modified code to check the return value of HandleD
| |
546 const StorageObjects& storage_objects = device_details->storage_objects; | |
547 const string16& name = device_details->name; | |
548 const string16& location = device_details->location; | |
Peter Kasting
2012/10/26 23:46:23
Nit: If any of these refs doesn't end up saving li
kmadhusu
2012/10/28 22:57:16
I would like to leave it as it is.
| |
549 DCHECK(!ContainsKey(device_map_, location)); | |
550 | |
551 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); | |
552 DCHECK(system_monitor); | |
553 for (StorageObjects::const_iterator storage_iter = storage_objects.begin(); | |
554 storage_iter != storage_objects.end(); ++storage_iter) { | |
555 const std::string& storage_id = storage_iter->object_persistent_id; | |
556 DCHECK(!ContainsKey(storage_map_, storage_id)); | |
557 | |
558 // Keep track of storage id and storage name to see how often we receive | |
559 // empty values. | |
560 MediaStorageUtil::RecordDeviceInfoHistogram(false, storage_id, name); | |
561 if (storage_id.empty() || name.empty()) | |
562 return; | |
563 | |
564 // Device can have several data partitions. Therefore, add the | |
565 // partition identifier to the storage name. E.g.: "Nexus 7 (s10001)" | |
566 string16 storage_name(name + L" (" + storage_iter->object_temporary_id + | |
567 L')'); | |
Peter Kasting
2012/10/26 23:46:23
Nit: Indent 4
kmadhusu
2012/10/28 22:57:16
Done.
| |
568 storage_map_[storage_id] = | |
569 base::SystemMonitor::RemovableStorageInfo(storage_id, storage_name, | |
570 location); | |
Peter Kasting
2012/10/26 23:46:23
Nit: Arg must be aligned with first arg above
kmadhusu
2012/10/28 22:57:16
Done.
| |
571 system_monitor->ProcessRemovableStorageAttached( | |
572 storage_id, storage_name, GetStoragePathFromStorageId(storage_id)); | |
573 } | |
574 device_map_[location] = storage_objects; | |
575 } | |
576 | |
577 void PortableDeviceWatcherWin::HandleDeviceDetachEvent( | |
578 const string16& pnp_device_id) { | |
579 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
580 MtpDeviceMap::iterator device_entry = device_map_.find(pnp_device_id); | |
581 if (device_entry == device_map_.end()) | |
582 return; | |
583 | |
584 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); | |
585 DCHECK(system_monitor); | |
586 | |
587 StorageObjects storage_objects = device_entry->second; | |
Peter Kasting
2012/10/26 23:46:23
Nit: Does the loop below modify or invalidate what
kmadhusu
2012/10/28 22:57:16
Loop does not modify |device_entry|->second value.
| |
588 for (StorageObjects::const_iterator storage_iter = storage_objects.begin(); | |
589 storage_iter != storage_objects.end(); ++storage_iter) { | |
590 std::string storage_id = storage_iter->object_persistent_id; | |
591 MtpStorageMap::iterator storage_entry = storage_map_.find(storage_id); | |
592 DCHECK(storage_entry != storage_map_.end()); | |
593 system_monitor->ProcessRemovableStorageDetached( | |
594 storage_entry->second.device_id); | |
595 storage_map_.erase(storage_entry); | |
596 } | |
597 device_map_.erase(device_entry); | |
598 } | |
599 | |
600 } // namespace chrome | |
OLD | NEW |