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

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

Powered by Google App Engine
This is Rietveld 408576698