Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(750)

Side by Side Diff: chrome/browser/system_monitor/portable_device_watcher_win.cc

Issue 11088012: [Win, MediaGallery] Enumerate and handle mtp device attach/detach events. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed review comments Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698