OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 // Any tasks that communicates with the portable device may take >100ms to | 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 | 6 // complete. Those tasks should be run on an blocking thread instead of the |
7 // UI thread. | 7 // UI thread. |
8 | 8 |
9 #include "components/storage_monitor/portable_device_watcher_win.h" | 9 #include "components/storage_monitor/portable_device_watcher_win.h" |
10 | 10 |
11 #include <dbt.h> | 11 #include <dbt.h> |
12 #include <objbase.h> | 12 #include <objbase.h> |
13 #include <portabledevice.h> | 13 #include <portabledevice.h> |
14 | 14 |
15 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
20 #include "base/threading/sequenced_worker_pool.h" | 20 #include "base/task_scheduler/post_task.h" |
| 21 #include "base/threading/thread_restrictions.h" |
21 #include "base/win/scoped_co_mem.h" | 22 #include "base/win/scoped_co_mem.h" |
22 #include "base/win/scoped_comptr.h" | 23 #include "base/win/scoped_comptr.h" |
23 #include "base/win/scoped_propvariant.h" | 24 #include "base/win/scoped_propvariant.h" |
24 #include "components/storage_monitor/removable_device_constants.h" | 25 #include "components/storage_monitor/removable_device_constants.h" |
25 #include "components/storage_monitor/storage_info.h" | 26 #include "components/storage_monitor/storage_info.h" |
26 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
27 | 28 |
28 namespace storage_monitor { | 29 namespace storage_monitor { |
29 | 30 |
30 namespace { | 31 namespace { |
31 | 32 |
32 // Name of the client application that communicates with the MTP device. | 33 // Name of the client application that communicates with the MTP device. |
33 const base::char16 kClientName[] = L"Chromium"; | 34 const base::char16 kClientName[] = L"Chromium"; |
34 | 35 |
35 // Name of the sequenced task runner. | |
36 const char kMediaTaskRunnerName[] = "media-task-runner"; | |
37 | |
38 // Returns true if |data| represents a class of portable devices. | 36 // Returns true if |data| represents a class of portable devices. |
39 bool IsPortableDeviceStructure(LPARAM data) { | 37 bool IsPortableDeviceStructure(LPARAM data) { |
40 DEV_BROADCAST_HDR* broadcast_hdr = | 38 DEV_BROADCAST_HDR* broadcast_hdr = |
41 reinterpret_cast<DEV_BROADCAST_HDR*>(data); | 39 reinterpret_cast<DEV_BROADCAST_HDR*>(data); |
42 if (!broadcast_hdr || | 40 if (!broadcast_hdr || |
43 (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) { | 41 (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) { |
44 return false; | 42 return false; |
45 } | 43 } |
46 | 44 |
47 GUID guidDevInterface = GUID_NULL; | 45 GUID guidDevInterface = GUID_NULL; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 // the volume name. | 308 // the volume name. |
311 return ((device_name.length() >= 2) && (device_name[1] == L':') && | 309 return ((device_name.length() >= 2) && (device_name[1] == L':') && |
312 (((device_name[0] >= L'A') && (device_name[0] <= L'Z')) || | 310 (((device_name[0] >= L'A') && (device_name[0] <= L'Z')) || |
313 ((device_name[0] >= L'a') && (device_name[0] <= L'z')))); | 311 ((device_name[0] >= L'a') && (device_name[0] <= L'z')))); |
314 } | 312 } |
315 | 313 |
316 // Returns the name of the device specified by |pnp_device_id|. | 314 // Returns the name of the device specified by |pnp_device_id|. |
317 base::string16 GetDeviceNameOnBlockingThread( | 315 base::string16 GetDeviceNameOnBlockingThread( |
318 IPortableDeviceManager* portable_device_manager, | 316 IPortableDeviceManager* portable_device_manager, |
319 const base::string16& pnp_device_id) { | 317 const base::string16& pnp_device_id) { |
320 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
321 DCHECK(portable_device_manager); | 318 DCHECK(portable_device_manager); |
| 319 base::ThreadRestrictions::AssertIOAllowed(); |
322 base::string16 name; | 320 base::string16 name; |
323 GetFriendlyName(pnp_device_id, portable_device_manager, &name) || | 321 GetFriendlyName(pnp_device_id, portable_device_manager, &name) || |
324 GetDeviceDescription(pnp_device_id, portable_device_manager, &name) || | 322 GetDeviceDescription(pnp_device_id, portable_device_manager, &name) || |
325 GetManufacturerName(pnp_device_id, portable_device_manager, &name); | 323 GetManufacturerName(pnp_device_id, portable_device_manager, &name); |
326 return name; | 324 return name; |
327 } | 325 } |
328 | 326 |
329 // Access the device and gets the device storage details. On success, returns | 327 // Access the device and gets the device storage details. On success, returns |
330 // true and populates |storage_objects| with device storage details. | 328 // true and populates |storage_objects| with device storage details. |
331 bool GetDeviceStorageObjectsOnBlockingThread( | 329 bool GetDeviceStorageObjectsOnBlockingThread( |
332 const base::string16& pnp_device_id, | 330 const base::string16& pnp_device_id, |
333 PortableDeviceWatcherWin::StorageObjects* storage_objects) { | 331 PortableDeviceWatcherWin::StorageObjects* storage_objects) { |
334 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
335 DCHECK(storage_objects); | 332 DCHECK(storage_objects); |
| 333 base::ThreadRestrictions::AssertIOAllowed(); |
336 base::win::ScopedComPtr<IPortableDevice> device; | 334 base::win::ScopedComPtr<IPortableDevice> device; |
337 if (!SetUp(pnp_device_id, &device)) | 335 if (!SetUp(pnp_device_id, &device)) |
338 return false; | 336 return false; |
339 | 337 |
340 base::string16 device_serial_num; | 338 base::string16 device_serial_num; |
341 if (!GetObjectUniqueId(device.Get(), WPD_DEVICE_OBJECT_ID, | 339 if (!GetObjectUniqueId(device.Get(), WPD_DEVICE_OBJECT_ID, |
342 &device_serial_num)) { | 340 &device_serial_num)) { |
343 return false; | 341 return false; |
344 } | 342 } |
345 | 343 |
(...skipping 16 matching lines...) Expand all Loading... |
362 return true; | 360 return true; |
363 } | 361 } |
364 | 362 |
365 // Accesses the device and gets the device details (name, storage info, etc). | 363 // Accesses the device and gets the device details (name, storage info, etc). |
366 // On success returns true and fills in |device_details|. On failure, returns | 364 // On success returns true and fills in |device_details|. On failure, returns |
367 // false. |pnp_device_id| specifies the plug and play device ID string. | 365 // false. |pnp_device_id| specifies the plug and play device ID string. |
368 bool GetDeviceInfoOnBlockingThread( | 366 bool GetDeviceInfoOnBlockingThread( |
369 IPortableDeviceManager* portable_device_manager, | 367 IPortableDeviceManager* portable_device_manager, |
370 const base::string16& pnp_device_id, | 368 const base::string16& pnp_device_id, |
371 PortableDeviceWatcherWin::DeviceDetails* device_details) { | 369 PortableDeviceWatcherWin::DeviceDetails* device_details) { |
372 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
373 DCHECK(portable_device_manager); | 370 DCHECK(portable_device_manager); |
374 DCHECK(device_details); | 371 DCHECK(device_details); |
375 DCHECK(!pnp_device_id.empty()); | 372 DCHECK(!pnp_device_id.empty()); |
| 373 base::ThreadRestrictions::AssertIOAllowed(); |
376 device_details->name = GetDeviceNameOnBlockingThread(portable_device_manager, | 374 device_details->name = GetDeviceNameOnBlockingThread(portable_device_manager, |
377 pnp_device_id); | 375 pnp_device_id); |
378 if (IsMassStoragePortableDevice(pnp_device_id, device_details->name)) | 376 if (IsMassStoragePortableDevice(pnp_device_id, device_details->name)) |
379 return false; | 377 return false; |
380 | 378 |
381 device_details->location = pnp_device_id; | 379 device_details->location = pnp_device_id; |
382 PortableDeviceWatcherWin::StorageObjects storage_objects; | 380 PortableDeviceWatcherWin::StorageObjects storage_objects; |
383 return GetDeviceStorageObjectsOnBlockingThread( | 381 return GetDeviceStorageObjectsOnBlockingThread( |
384 pnp_device_id, &device_details->storage_objects); | 382 pnp_device_id, &device_details->storage_objects); |
385 } | 383 } |
386 | 384 |
387 // Wrapper function to get an instance of portable device manager. On success, | 385 // Wrapper function to get an instance of portable device manager. On success, |
388 // returns true and fills in |portable_device_mgr|. On failure, returns false. | 386 // returns true and fills in |portable_device_mgr|. On failure, returns false. |
389 bool GetPortableDeviceManager( | 387 bool GetPortableDeviceManager( |
390 base::win::ScopedComPtr<IPortableDeviceManager>* portable_device_mgr) { | 388 base::win::ScopedComPtr<IPortableDeviceManager>* portable_device_mgr) { |
391 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | 389 base::ThreadRestrictions::AssertIOAllowed(); |
392 HRESULT hr = ::CoCreateInstance( | 390 HRESULT hr = ::CoCreateInstance( |
393 __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER, | 391 __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER, |
394 IID_PPV_ARGS(portable_device_mgr->GetAddressOf())); | 392 IID_PPV_ARGS(portable_device_mgr->GetAddressOf())); |
395 if (SUCCEEDED(hr)) | 393 if (SUCCEEDED(hr)) |
396 return true; | 394 return true; |
397 | 395 |
398 // Either there is no portable device support (Windows XP with old versions of | 396 // Either there is no portable device support (Windows XP with old versions of |
399 // Media Player) or the thread does not have COM initialized. | 397 // Media Player) or the thread does not have COM initialized. |
400 DCHECK_NE(CO_E_NOTINITIALIZED, hr); | 398 DCHECK_NE(CO_E_NOTINITIALIZED, hr); |
401 return false; | 399 return false; |
402 } | 400 } |
403 | 401 |
404 // Enumerates the attached portable devices. On success, returns true and fills | 402 // Enumerates the attached portable devices. On success, returns true and fills |
405 // in |devices| with the attached portable device details. On failure, returns | 403 // in |devices| with the attached portable device details. On failure, returns |
406 // false. | 404 // false. |
407 bool EnumerateAttachedDevicesOnBlockingThread( | 405 bool EnumerateAttachedDevicesOnBlockingThread( |
408 PortableDeviceWatcherWin::Devices* devices) { | 406 PortableDeviceWatcherWin::Devices* devices) { |
409 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
410 DCHECK(devices); | 407 DCHECK(devices); |
| 408 base::ThreadRestrictions::AssertIOAllowed(); |
411 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; | 409 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; |
412 if (!GetPortableDeviceManager(&portable_device_mgr)) | 410 if (!GetPortableDeviceManager(&portable_device_mgr)) |
413 return false; | 411 return false; |
414 | 412 |
415 // Get the total number of devices found on the system. | 413 // Get the total number of devices found on the system. |
416 DWORD pnp_device_count = 0; | 414 DWORD pnp_device_count = 0; |
417 HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count); | 415 HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count); |
418 if (FAILED(hr)) | 416 if (FAILED(hr)) |
419 return false; | 417 return false; |
420 | 418 |
(...skipping 13 matching lines...) Expand all Loading... |
434 return !devices->empty(); | 432 return !devices->empty(); |
435 } | 433 } |
436 | 434 |
437 // Handles the device attach event message on a media task runner. | 435 // Handles the device attach event message on a media task runner. |
438 // |pnp_device_id| specifies the attached plug and play device ID string. On | 436 // |pnp_device_id| specifies the attached plug and play device ID string. On |
439 // success, returns true and populates |device_details| with device information. | 437 // success, returns true and populates |device_details| with device information. |
440 // On failure, returns false. | 438 // On failure, returns false. |
441 bool HandleDeviceAttachedEventOnBlockingThread( | 439 bool HandleDeviceAttachedEventOnBlockingThread( |
442 const base::string16& pnp_device_id, | 440 const base::string16& pnp_device_id, |
443 PortableDeviceWatcherWin::DeviceDetails* device_details) { | 441 PortableDeviceWatcherWin::DeviceDetails* device_details) { |
444 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
445 DCHECK(device_details); | 442 DCHECK(device_details); |
| 443 base::ThreadRestrictions::AssertIOAllowed(); |
446 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; | 444 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; |
447 if (!GetPortableDeviceManager(&portable_device_mgr)) | 445 if (!GetPortableDeviceManager(&portable_device_mgr)) |
448 return false; | 446 return false; |
449 // Sometimes, portable device manager doesn't have the new device details. | 447 // Sometimes, portable device manager doesn't have the new device details. |
450 // Refresh the manager device list to update its details. | 448 // Refresh the manager device list to update its details. |
451 portable_device_mgr->RefreshDeviceList(); | 449 portable_device_mgr->RefreshDeviceList(); |
452 return GetDeviceInfoOnBlockingThread(portable_device_mgr.Get(), pnp_device_id, | 450 return GetDeviceInfoOnBlockingThread(portable_device_mgr.Get(), pnp_device_id, |
453 device_details); | 451 device_details); |
454 } | 452 } |
455 | 453 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 weak_ptr_factory_(this) { | 494 weak_ptr_factory_(this) { |
497 } | 495 } |
498 | 496 |
499 PortableDeviceWatcherWin::~PortableDeviceWatcherWin() { | 497 PortableDeviceWatcherWin::~PortableDeviceWatcherWin() { |
500 UnregisterDeviceNotification(notifications_); | 498 UnregisterDeviceNotification(notifications_); |
501 } | 499 } |
502 | 500 |
503 void PortableDeviceWatcherWin::Init(HWND hwnd) { | 501 void PortableDeviceWatcherWin::Init(HWND hwnd) { |
504 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 502 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
505 notifications_ = RegisterPortableDeviceNotification(hwnd); | 503 notifications_ = RegisterPortableDeviceNotification(hwnd); |
506 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); | 504 media_task_runner_ = base::CreateSequencedTaskRunnerWithTraits( |
507 media_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior( | 505 {base::MayBlock(), base::TaskPriority::BACKGROUND, |
508 pool->GetNamedSequenceToken(kMediaTaskRunnerName), | 506 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}); |
509 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | |
510 EnumerateAttachedDevices(); | 507 EnumerateAttachedDevices(); |
511 } | 508 } |
512 | 509 |
513 void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { | 510 void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { |
514 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 511 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
515 if (!IsPortableDeviceStructure(data)) | 512 if (!IsPortableDeviceStructure(data)) |
516 return; | 513 return; |
517 | 514 |
518 base::string16 device_id = GetPnpDeviceId(data); | 515 base::string16 device_id = GetPnpDeviceId(data); |
519 if (event_type == DBT_DEVICEARRIVAL) | 516 if (event_type == DBT_DEVICEARRIVAL) |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 if (storage_notifications_) { | 667 if (storage_notifications_) { |
671 storage_notifications_->ProcessDetach( | 668 storage_notifications_->ProcessDetach( |
672 storage_map_iter->second.device_id()); | 669 storage_map_iter->second.device_id()); |
673 } | 670 } |
674 storage_map_.erase(storage_map_iter); | 671 storage_map_.erase(storage_map_iter); |
675 } | 672 } |
676 device_map_.erase(device_iter); | 673 device_map_.erase(device_iter); |
677 } | 674 } |
678 | 675 |
679 } // namespace storage_monitor | 676 } // namespace storage_monitor |
OLD | NEW |