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/win/scoped_co_mem.h" | 21 #include "base/win/scoped_co_mem.h" |
22 #include "base/win/scoped_comptr.h" | 22 #include "base/win/scoped_comptr.h" |
23 #include "base/win/scoped_propvariant.h" | 23 #include "base/win/scoped_propvariant.h" |
24 #include "components/storage_monitor/removable_device_constants.h" | 24 #include "components/storage_monitor/removable_device_constants.h" |
25 #include "components/storage_monitor/storage_info.h" | 25 #include "components/storage_monitor/storage_info.h" |
26 #include "content/public/browser/browser_thread.h" | 26 #include "content/public/browser/browser_thread.h" |
27 | 27 |
28 namespace storage_monitor { | 28 namespace storage_monitor { |
29 | 29 |
30 namespace { | 30 namespace { |
31 | 31 |
32 // Name of the client application that communicates with the MTP device. | 32 // Name of the client application that communicates with the MTP device. |
33 const base::char16 kClientName[] = L"Chromium"; | 33 const base::char16 kClientName[] = L"Chromium"; |
34 | 34 |
35 // Name of the sequenced task runner. | 35 // Name of the sequenced task runner. |
36 const char kMediaTaskRunnerName[] = "media-task-runner"; | 36 const char kMediaTaskRunnerName[] = "media-task-runner"; |
Lei Zhang
2017/06/19 18:24:46
I think this needs to be removed too.
Yeol Park
2017/06/20 09:04:42
Done.
| |
37 | 37 |
38 // Returns true if |data| represents a class of portable devices. | 38 // Returns true if |data| represents a class of portable devices. |
39 bool IsPortableDeviceStructure(LPARAM data) { | 39 bool IsPortableDeviceStructure(LPARAM data) { |
40 DEV_BROADCAST_HDR* broadcast_hdr = | 40 DEV_BROADCAST_HDR* broadcast_hdr = |
41 reinterpret_cast<DEV_BROADCAST_HDR*>(data); | 41 reinterpret_cast<DEV_BROADCAST_HDR*>(data); |
42 if (!broadcast_hdr || | 42 if (!broadcast_hdr || |
43 (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) { | 43 (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) { |
44 return false; | 44 return false; |
45 } | 45 } |
46 | 46 |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 // the volume name. | 310 // the volume name. |
311 return ((device_name.length() >= 2) && (device_name[1] == L':') && | 311 return ((device_name.length() >= 2) && (device_name[1] == L':') && |
312 (((device_name[0] >= L'A') && (device_name[0] <= L'Z')) || | 312 (((device_name[0] >= L'A') && (device_name[0] <= L'Z')) || |
313 ((device_name[0] >= L'a') && (device_name[0] <= L'z')))); | 313 ((device_name[0] >= L'a') && (device_name[0] <= L'z')))); |
314 } | 314 } |
315 | 315 |
316 // Returns the name of the device specified by |pnp_device_id|. | 316 // Returns the name of the device specified by |pnp_device_id|. |
317 base::string16 GetDeviceNameOnBlockingThread( | 317 base::string16 GetDeviceNameOnBlockingThread( |
318 IPortableDeviceManager* portable_device_manager, | 318 IPortableDeviceManager* portable_device_manager, |
319 const base::string16& pnp_device_id) { | 319 const base::string16& pnp_device_id) { |
320 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
Lei Zhang
2017/06/19 18:24:46
Can we retain some kind of DCHECK to help make sur
fdoray
2017/06/19 18:35:02
DCHECK(media_task_runner_->RunsTasksInCurrentSeque
Yeol Park
2017/06/20 09:04:42
Done.
Yeol Park
2017/06/20 09:04:42
Done.
| |
321 DCHECK(portable_device_manager); | 320 DCHECK(portable_device_manager); |
322 base::string16 name; | 321 base::string16 name; |
323 GetFriendlyName(pnp_device_id, portable_device_manager, &name) || | 322 GetFriendlyName(pnp_device_id, portable_device_manager, &name) || |
324 GetDeviceDescription(pnp_device_id, portable_device_manager, &name) || | 323 GetDeviceDescription(pnp_device_id, portable_device_manager, &name) || |
325 GetManufacturerName(pnp_device_id, portable_device_manager, &name); | 324 GetManufacturerName(pnp_device_id, portable_device_manager, &name); |
326 return name; | 325 return name; |
327 } | 326 } |
328 | 327 |
329 // Access the device and gets the device storage details. On success, returns | 328 // Access the device and gets the device storage details. On success, returns |
330 // true and populates |storage_objects| with device storage details. | 329 // true and populates |storage_objects| with device storage details. |
331 bool GetDeviceStorageObjectsOnBlockingThread( | 330 bool GetDeviceStorageObjectsOnBlockingThread( |
332 const base::string16& pnp_device_id, | 331 const base::string16& pnp_device_id, |
333 PortableDeviceWatcherWin::StorageObjects* storage_objects) { | 332 PortableDeviceWatcherWin::StorageObjects* storage_objects) { |
334 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
335 DCHECK(storage_objects); | 333 DCHECK(storage_objects); |
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 } |
(...skipping 17 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()); |
376 device_details->name = GetDeviceNameOnBlockingThread(portable_device_manager, | 373 device_details->name = GetDeviceNameOnBlockingThread(portable_device_manager, |
377 pnp_device_id); | 374 pnp_device_id); |
378 if (IsMassStoragePortableDevice(pnp_device_id, device_details->name)) | 375 if (IsMassStoragePortableDevice(pnp_device_id, device_details->name)) |
379 return false; | 376 return false; |
380 | 377 |
381 device_details->location = pnp_device_id; | 378 device_details->location = pnp_device_id; |
382 PortableDeviceWatcherWin::StorageObjects storage_objects; | 379 PortableDeviceWatcherWin::StorageObjects storage_objects; |
383 return GetDeviceStorageObjectsOnBlockingThread( | 380 return GetDeviceStorageObjectsOnBlockingThread( |
384 pnp_device_id, &device_details->storage_objects); | 381 pnp_device_id, &device_details->storage_objects); |
385 } | 382 } |
386 | 383 |
387 // Wrapper function to get an instance of portable device manager. On success, | 384 // 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. | 385 // returns true and fills in |portable_device_mgr|. On failure, returns false. |
389 bool GetPortableDeviceManager( | 386 bool GetPortableDeviceManager( |
390 base::win::ScopedComPtr<IPortableDeviceManager>* portable_device_mgr) { | 387 base::win::ScopedComPtr<IPortableDeviceManager>* portable_device_mgr) { |
391 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
392 HRESULT hr = ::CoCreateInstance( | 388 HRESULT hr = ::CoCreateInstance( |
393 __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER, | 389 __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER, |
394 IID_PPV_ARGS(portable_device_mgr->GetAddressOf())); | 390 IID_PPV_ARGS(portable_device_mgr->GetAddressOf())); |
395 if (SUCCEEDED(hr)) | 391 if (SUCCEEDED(hr)) |
396 return true; | 392 return true; |
397 | 393 |
398 // Either there is no portable device support (Windows XP with old versions of | 394 // Either there is no portable device support (Windows XP with old versions of |
399 // Media Player) or the thread does not have COM initialized. | 395 // Media Player) or the thread does not have COM initialized. |
400 DCHECK_NE(CO_E_NOTINITIALIZED, hr); | 396 DCHECK_NE(CO_E_NOTINITIALIZED, hr); |
401 return false; | 397 return false; |
402 } | 398 } |
403 | 399 |
404 // Enumerates the attached portable devices. On success, returns true and fills | 400 // Enumerates the attached portable devices. On success, returns true and fills |
405 // in |devices| with the attached portable device details. On failure, returns | 401 // in |devices| with the attached portable device details. On failure, returns |
406 // false. | 402 // false. |
407 bool EnumerateAttachedDevicesOnBlockingThread( | 403 bool EnumerateAttachedDevicesOnBlockingThread( |
408 PortableDeviceWatcherWin::Devices* devices) { | 404 PortableDeviceWatcherWin::Devices* devices) { |
409 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
410 DCHECK(devices); | 405 DCHECK(devices); |
411 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; | 406 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; |
412 if (!GetPortableDeviceManager(&portable_device_mgr)) | 407 if (!GetPortableDeviceManager(&portable_device_mgr)) |
413 return false; | 408 return false; |
414 | 409 |
415 // Get the total number of devices found on the system. | 410 // Get the total number of devices found on the system. |
416 DWORD pnp_device_count = 0; | 411 DWORD pnp_device_count = 0; |
417 HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count); | 412 HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count); |
418 if (FAILED(hr)) | 413 if (FAILED(hr)) |
419 return false; | 414 return false; |
(...skipping 14 matching lines...) Expand all Loading... | |
434 return !devices->empty(); | 429 return !devices->empty(); |
435 } | 430 } |
436 | 431 |
437 // Handles the device attach event message on a media task runner. | 432 // 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 | 433 // |pnp_device_id| specifies the attached plug and play device ID string. On |
439 // success, returns true and populates |device_details| with device information. | 434 // success, returns true and populates |device_details| with device information. |
440 // On failure, returns false. | 435 // On failure, returns false. |
441 bool HandleDeviceAttachedEventOnBlockingThread( | 436 bool HandleDeviceAttachedEventOnBlockingThread( |
442 const base::string16& pnp_device_id, | 437 const base::string16& pnp_device_id, |
443 PortableDeviceWatcherWin::DeviceDetails* device_details) { | 438 PortableDeviceWatcherWin::DeviceDetails* device_details) { |
444 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
445 DCHECK(device_details); | 439 DCHECK(device_details); |
446 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; | 440 base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; |
447 if (!GetPortableDeviceManager(&portable_device_mgr)) | 441 if (!GetPortableDeviceManager(&portable_device_mgr)) |
448 return false; | 442 return false; |
449 // Sometimes, portable device manager doesn't have the new device details. | 443 // Sometimes, portable device manager doesn't have the new device details. |
450 // Refresh the manager device list to update its details. | 444 // Refresh the manager device list to update its details. |
451 portable_device_mgr->RefreshDeviceList(); | 445 portable_device_mgr->RefreshDeviceList(); |
452 return GetDeviceInfoOnBlockingThread(portable_device_mgr.Get(), pnp_device_id, | 446 return GetDeviceInfoOnBlockingThread(portable_device_mgr.Get(), pnp_device_id, |
453 device_details); | 447 device_details); |
454 } | 448 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
496 weak_ptr_factory_(this) { | 490 weak_ptr_factory_(this) { |
497 } | 491 } |
498 | 492 |
499 PortableDeviceWatcherWin::~PortableDeviceWatcherWin() { | 493 PortableDeviceWatcherWin::~PortableDeviceWatcherWin() { |
500 UnregisterDeviceNotification(notifications_); | 494 UnregisterDeviceNotification(notifications_); |
501 } | 495 } |
502 | 496 |
503 void PortableDeviceWatcherWin::Init(HWND hwnd) { | 497 void PortableDeviceWatcherWin::Init(HWND hwnd) { |
504 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 498 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
505 notifications_ = RegisterPortableDeviceNotification(hwnd); | 499 notifications_ = RegisterPortableDeviceNotification(hwnd); |
506 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); | 500 media_task_runner_ = base::CreateSequencedTaskRunnerWithTraits( |
fdoray
2017/06/19 18:35:02
Do tasks posted to this TaskRunner need to run in
Yeol Park
2017/06/20 09:04:42
I used LazySequencedTaskRunner instead of Sequence
fdoray
2017/06/20 12:15:02
Previously, |media_task_runner_| was created with
Yeol Park
2017/06/21 02:34:32
Done.
fdoray
2017/06/21 12:26:59
Is it an issue that with your CL, tasks posted to
| |
507 media_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior( | 501 {base::MayBlock(), base::TaskPriority::BACKGROUND, |
508 pool->GetNamedSequenceToken(kMediaTaskRunnerName), | 502 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}) |
509 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | 503 .get(); |
fdoray
2017/06/19 18:35:02
no .get()
Yeol Park
2017/06/20 09:04:42
Done.
| |
510 EnumerateAttachedDevices(); | 504 EnumerateAttachedDevices(); |
511 } | 505 } |
512 | 506 |
513 void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { | 507 void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { |
514 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 508 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
515 if (!IsPortableDeviceStructure(data)) | 509 if (!IsPortableDeviceStructure(data)) |
516 return; | 510 return; |
517 | 511 |
518 base::string16 device_id = GetPnpDeviceId(data); | 512 base::string16 device_id = GetPnpDeviceId(data); |
519 if (event_type == DBT_DEVICEARRIVAL) | 513 if (event_type == DBT_DEVICEARRIVAL) |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
670 if (storage_notifications_) { | 664 if (storage_notifications_) { |
671 storage_notifications_->ProcessDetach( | 665 storage_notifications_->ProcessDetach( |
672 storage_map_iter->second.device_id()); | 666 storage_map_iter->second.device_id()); |
673 } | 667 } |
674 storage_map_.erase(storage_map_iter); | 668 storage_map_.erase(storage_map_iter); |
675 } | 669 } |
676 device_map_.erase(device_iter); | 670 device_map_.erase(device_iter); |
677 } | 671 } |
678 | 672 |
679 } // namespace storage_monitor | 673 } // namespace storage_monitor |
OLD | NEW |