| 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 |