portable_device_watcher_win.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Any tasks that communicates with the portable device may take >100ms to 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// complete. Those tasks should be run on an blocking thread instead of the 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UI thread. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/storage_monitor/portable_device_watcher_win.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dbt.h> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <portabledevice.h> 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_co_mem.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_propvariant.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/storage_monitor/media_storage_util.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/storage_monitor/removable_device_constants.h" 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/storage_monitor/storage_info.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Name of the client application that communicates with the MTP device. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char16 kClientName[] = L"Chromium"; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Name of the sequenced task runner. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kMediaTaskRunnerName[] = "media-task-runner"; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |data| represents a class of portable devices. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsPortableDeviceStructure(LPARAM data) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEV_BROADCAST_HDR* broadcast_hdr = 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<DEV_BROADCAST_HDR*>(data); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!broadcast_hdr || 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GUID guidDevInterface = GUID_NULL; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface))) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEV_BROADCAST_DEVICEINTERFACE* dev_interface = 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (IsEqualGUID(dev_interface->dbcc_classguid, guidDevInterface) != 0); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the portable device plug and play device ID string. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 GetPnpDeviceId(LPARAM data) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEV_BROADCAST_DEVICEINTERFACE* dev_interface = 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!dev_interface) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return string16(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 device_id(dev_interface->dbcc_name); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsStringASCII(device_id)); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return StringToLowerASCII(device_id); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the friendly name of the device specified by the |pnp_device_id|. On 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// success, returns true and fills in |name|. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetFriendlyName(const string16& pnp_device_id, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPortableDeviceManager* device_manager, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* name) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_manager); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(name); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD name_len = 0; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = device_manager->GetDeviceFriendlyName(pnp_device_id.c_str(), 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, &name_len); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = device_manager->GetDeviceFriendlyName( 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pnp_device_id.c_str(), WriteInto(name, name_len), &name_len); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (SUCCEEDED(hr) && !name->empty()); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the manufacturer name of the device specified by the |pnp_device_id|. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success, returns true and fills in |name|. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetManufacturerName(const string16& pnp_device_id, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPortableDeviceManager* device_manager, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* name) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_manager); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(name); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD name_len = 0; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = device_manager->GetDeviceManufacturer(pnp_device_id.c_str(), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, &name_len); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = device_manager->GetDeviceManufacturer(pnp_device_id.c_str(), 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteInto(name, name_len), 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &name_len); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (SUCCEEDED(hr) && !name->empty()); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the description of the device specified by the |pnp_device_id|. On 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// success, returns true and fills in |description|. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetDeviceDescription(const string16& pnp_device_id, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPortableDeviceManager* device_manager, 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* description) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_manager); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(description); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD desc_len = 0; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(), NULL, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &desc_len); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(), 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteInto(description, desc_len), 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &desc_len); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (SUCCEEDED(hr) && !description->empty()); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success, returns true and updates |client_info| with a reference to an 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IPortableDeviceValues interface that holds information about the 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// application that communicates with the device. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetClientInformation( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceValues>* client_info) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = client_info->CreateInstance(__uuidof(PortableDeviceValues), 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, CLSCTX_INPROC_SERVER); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to create an instance of IPortableDeviceValues"; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Attempt to set client details. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*client_info)->SetStringValue(WPD_CLIENT_NAME, kClientName); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, 0); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, 0); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, 0); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*client_info)->SetUnsignedIntegerValue( 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GENERIC_READ); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Opens the device for communication. |pnp_device_id| specifies the plug and 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// play device ID string. On success, returns true and updates |device| with a 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// reference to the portable device interface. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetUp(const string16& pnp_device_id, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDevice>* device) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceValues> client_info; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetClientInformation(&client_info)) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = device->CreateInstance(__uuidof(PortableDevice), NULL, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CLSCTX_INPROC_SERVER); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to create an instance of IPortableDevice"; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = (*device)->Open(pnp_device_id.c_str(), client_info.get()); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SUCCEEDED(hr)) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hr == E_ACCESSDENIED) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Access denied to open the device"; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the unique id property key of the object specified by the 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |object_id|. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)REFPROPERTYKEY GetUniqueIdPropertyKey(const string16& object_id) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (object_id == WPD_DEVICE_OBJECT_ID) ? 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WPD_DEVICE_SERIAL_NUMBER : WPD_OBJECT_PERSISTENT_UNIQUE_ID; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success, returns true and populates |properties_to_read| with the 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// property key of the object specified by the |object_id|. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PopulatePropertyKeyCollection( 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& object_id, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceKeyCollection>* properties_to_read) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = properties_to_read->CreateInstance( 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __uuidof(PortableDeviceKeyCollection), NULL, CLSCTX_INPROC_SERVER); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to create IPortableDeviceKeyCollection instance"; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) REFPROPERTYKEY key = GetUniqueIdPropertyKey(object_id); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = (*properties_to_read)->Add(key); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SUCCEEDED(hr); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wrapper function to get content property string value. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetStringPropertyValue(IPortableDeviceValues* properties_values, 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) REFPROPERTYKEY key, 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* value) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(properties_values); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(value); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedCoMem<char16> buffer; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = properties_values->GetStringValue(key, &buffer); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *value = static_cast<const char16*>(buffer); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Constructs a unique identifier for the object specified by the |object_id|. 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success, returns true and fills in |unique_id|. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetObjectUniqueId(IPortableDevice* device, 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& object_id, 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* unique_id) { 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(unique_id); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceContent> content; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = device->Content(content.Receive()); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to get IPortableDeviceContent interface"; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceProperties> properties; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = content->Properties(properties.Receive()); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to get IPortableDeviceProperties interface"; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceKeyCollection> properties_to_read; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PopulatePropertyKeyCollection(object_id, &properties_to_read)) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceValues> properties_values; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(properties->GetValues(object_id.c_str(), 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties_to_read.get(), 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties_values.Receive()))) { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) REFPROPERTYKEY key = GetUniqueIdPropertyKey(object_id); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetStringPropertyValue(properties_values.get(), key, unique_id); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Constructs the device storage unique identifier using |device_serial_num| and 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |storage_id|. On success, returns true and fills in |device_storage_id|. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ConstructDeviceStorageUniqueId(const string16& device_serial_num, 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& storage_id, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* device_storage_id) { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_serial_num.empty() && storage_id.empty()) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_storage_id); 25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *device_storage_id = StorageInfo::MakeDeviceId( 25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) StorageInfo::MTP_OR_PTP, 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UTF16ToUTF8(storage_id + L':' + device_serial_num)); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets a list of removable storage object identifiers present in |device|. 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success, returns true and fills in |storage_object_ids|. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetRemovableStorageObjectIds( 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPortableDevice* device, 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::StorageObjectIDs* storage_object_ids) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(storage_object_ids); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceCapabilities> capabilities; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = device->Capabilities(capabilities.Receive()); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to get IPortableDeviceCapabilities interface"; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDevicePropVariantCollection> storage_ids; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = capabilities->GetFunctionalObjects(WPD_FUNCTIONAL_CATEGORY_STORAGE, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_ids.Receive()); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "Failed to get IPortableDevicePropVariantCollection"; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD num_storage_obj_ids = 0; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = storage_ids->GetCount(&num_storage_obj_ids); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DWORD index = 0; index < num_storage_obj_ids; ++index) { 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedPropVariant object_id; 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = storage_ids->GetAt(index, object_id.Receive()); 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr) && object_id.get().vt == VT_LPWSTR && 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) object_id.get().pwszVal != NULL) { 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) storage_object_ids->push_back(object_id.get().pwszVal); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if the portable device belongs to a mass storage class. 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |pnp_device_id| specifies the plug and play device id. 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |device_name| specifies the name of the device. 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsMassStoragePortableDevice(const string16& pnp_device_id, 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const string16& device_name) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Based on testing, if the pnp device id starts with "\\?\wpdbusenumroot#", 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // then the attached device belongs to a mass storage class. 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (StartsWith(pnp_device_id, L"\\\\?\\wpdbusenumroot#", false)) 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the device is a volume mounted device, |device_name| will be 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the volume name. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((device_name.length() >= 2) && (device_name[1] == L':') && 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (((device_name[0] >= L'A') && (device_name[0] <= L'Z')) || 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((device_name[0] >= L'a') && (device_name[0] <= L'z')))); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the name of the device specified by |pnp_device_id|. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 GetDeviceNameOnBlockingThread( 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPortableDeviceManager* portable_device_manager, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& pnp_device_id) { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(portable_device_manager); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 name; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetFriendlyName(pnp_device_id, portable_device_manager, &name) || 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDeviceDescription(pnp_device_id, portable_device_manager, &name) || 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetManufacturerName(pnp_device_id, portable_device_manager, &name); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return name; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Access the device and gets the device storage details. On success, returns 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// true and populates |storage_objects| with device storage details. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetDeviceStorageObjectsOnBlockingThread( 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& pnp_device_id, 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::StorageObjects* storage_objects) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(storage_objects); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDevice> device; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SetUp(pnp_device_id, &device)) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 device_serial_num; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetObjectUniqueId(device.get(), WPD_DEVICE_OBJECT_ID, 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &device_serial_num)) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::StorageObjectIDs storage_obj_ids; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetRemovableStorageObjectIds(device.get(), &storage_obj_ids)) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PortableDeviceWatcherWin::StorageObjectIDs::const_iterator id_iter = 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_obj_ids.begin(); id_iter != storage_obj_ids.end(); ++id_iter) { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 storage_persistent_id; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetObjectUniqueId(device.get(), *id_iter, &storage_persistent_id)) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string device_storage_id; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ConstructDeviceStorageUniqueId(device_serial_num, storage_persistent_id, 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &device_storage_id)) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_objects->push_back(PortableDeviceWatcherWin::DeviceStorageObject( 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *id_iter, device_storage_id)); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Accesses the device and gets the device details (name, storage info, etc). 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On success returns true and fills in |device_details|. On failure, returns 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// false. |pnp_device_id| specifies the plug and play device ID string. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetDeviceInfoOnBlockingThread( 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPortableDeviceManager* portable_device_manager, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& pnp_device_id, 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::DeviceDetails* device_details) { 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(portable_device_manager); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_details); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!pnp_device_id.empty()); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_details->name = GetDeviceNameOnBlockingThread(portable_device_manager, 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pnp_device_id); 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsMassStoragePortableDevice(pnp_device_id, device_details->name)) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_details->location = pnp_device_id; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::StorageObjects storage_objects; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDeviceStorageObjectsOnBlockingThread( 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pnp_device_id, &device_details->storage_objects); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wrapper function to get an instance of portable device manager. On success, 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns true and fills in |portable_device_mgr|. On failure, returns false. 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetPortableDeviceManager( 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceManager>* portable_device_mgr) { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = portable_device_mgr->CreateInstance( 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SUCCEEDED(hr)) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either there is no portable device support (Windows XP with old versions of 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Media Player) or the thread does not have COM initialized. 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(CO_E_NOTINITIALIZED, hr); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Enumerates the attached portable devices. On success, returns true and fills 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in |devices| with the attached portable device details. On failure, returns 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// false. 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EnumerateAttachedDevicesOnBlockingThread( 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::Devices* devices) { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(devices); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetPortableDeviceManager(&portable_device_mgr)) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the total number of devices found on the system. 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD pnp_device_count = 0; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<char16*[]> pnp_device_ids(new char16*[pnp_device_count]); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = portable_device_mgr->GetDevices(pnp_device_ids.get(), &pnp_device_count); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DWORD index = 0; index < pnp_device_count; ++index) { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::DeviceDetails device_details; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetDeviceInfoOnBlockingThread( 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) portable_device_mgr, pnp_device_ids[index], &device_details)) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) devices->push_back(device_details); 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CoTaskMemFree(pnp_device_ids[index]); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !devices->empty(); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handles the device attach event message on a media task runner. 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |pnp_device_id| specifies the attached plug and play device ID string. On 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// success, returns true and populates |device_details| with device information. 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On failure, returns false. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HandleDeviceAttachedEventOnBlockingThread( 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& pnp_device_id, 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PortableDeviceWatcherWin::DeviceDetails* device_details) { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_details); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetPortableDeviceManager(&portable_device_mgr)) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sometimes, portable device manager doesn't have the new device details. 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Refresh the manager device list to update its details. 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) portable_device_mgr->RefreshDeviceList(); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDeviceInfoOnBlockingThread(portable_device_mgr, pnp_device_id, 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_details); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Registers |hwnd| to receive portable device notification details. On success, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns the device notifications handle else returns NULL. 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HDEVNOTIFY RegisterPortableDeviceNotification(HWND hwnd) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GUID dev_interface_guid = GUID_NULL; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &dev_interface_guid); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEV_BROADCAST_DEVICEINTERFACE db = { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(DEV_BROADCAST_DEVICEINTERFACE), 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DBT_DEVTYP_DEVICEINTERFACE, 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev_interface_guid 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return RegisterDeviceNotification(hwnd, &db, DEVICE_NOTIFY_WINDOW_HANDLE); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PortableDeviceWatcherWin --------------------------------------------------- 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PortableDeviceWatcherWin::DeviceStorageObject::DeviceStorageObject( 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& temporary_id, 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& persistent_id) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : object_temporary_id(temporary_id), 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) object_persistent_id(persistent_id) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PortableDeviceWatcherWin::PortableDeviceWatcherWin() 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : notifications_(NULL), 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) storage_notifications_(NULL), 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PortableDeviceWatcherWin::~PortableDeviceWatcherWin() { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnregisterDeviceNotification(notifications_); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::Init(HWND hwnd) { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notifications_ = RegisterPortableDeviceNotification(hwnd); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior( 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pool->GetNamedSequenceToken(kMediaTaskRunnerName), 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnumerateAttachedDevices(); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsPortableDeviceStructure(data)) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 device_id = GetPnpDeviceId(data); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event_type == DBT_DEVICEARRIVAL) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleDeviceAttachEvent(device_id); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (event_type == DBT_DEVICEREMOVECOMPLETE) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleDeviceDetachEvent(device_id); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool PortableDeviceWatcherWin::GetMTPStorageInfoFromDeviceId( 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& storage_device_id, 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16* device_location, 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16* storage_object_id) const { 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(device_location); 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(storage_object_id); 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MTPStorageMap::const_iterator storage_map_iter = 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) storage_map_.find(storage_device_id); 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (storage_map_iter == storage_map_.end()) 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MTPDeviceMap::const_iterator device_iter = 52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) device_map_.find(storage_map_iter->second.location()); 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (device_iter == device_map_.end()) 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const StorageObjects& storage_objects = device_iter->second; 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (StorageObjects::const_iterator storage_object_iter = 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) storage_objects.begin(); storage_object_iter != storage_objects.end(); 5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++storage_object_iter) { 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (storage_device_id == storage_object_iter->object_persistent_id) { 53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *device_location = storage_map_iter->second.location(); 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *storage_object_id = storage_object_iter->object_temporary_id; 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 PortableDeviceWatcherWin::GetStoragePathFromStorageId( 5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& storage_unique_id) { 5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Construct a dummy device path using the storage name. This is only used 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // for registering the device media file system. 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!storage_unique_id.empty()); 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return UTF8ToUTF16("\\\\" + storage_unique_id); 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PortableDeviceWatcherWin::SetNotifications( 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StorageMonitor::Receiver* notifications) { 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) storage_notifications_ = notifications; 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 555b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PortableDeviceWatcherWin::EjectDevice( 556b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const std::string& device_id, 557b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Callback<void(StorageMonitor::EjectStatus)> callback) { 558b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) callback.Run(chrome::StorageMonitor::EJECT_FAILURE); 559b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 560b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::EnumerateAttachedDevices() { 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(media_task_runner_.get()); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Devices* devices = new Devices; 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PostTaskAndReplyWithResult( 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media_task_runner_, 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&EnumerateAttachedDevicesOnBlockingThread, devices), 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices, 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), base::Owned(devices))); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices( 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Devices* devices, const bool result) { 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(devices); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Devices::const_iterator device_iter = devices->begin(); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_iter != devices->end(); ++device_iter) { 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnDidHandleDeviceAttachEvent(&(*device_iter), result); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::HandleDeviceAttachEvent( 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& pnp_device_id) { 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(media_task_runner_.get()); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeviceDetails* device_details = new DeviceDetails; 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PostTaskAndReplyWithResult( 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media_task_runner_, 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&HandleDeviceAttachedEventOnBlockingThread, pnp_device_id, 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_details), 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&PortableDeviceWatcherWin::OnDidHandleDeviceAttachEvent, 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), base::Owned(device_details))); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::OnDidHandleDeviceAttachEvent( 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DeviceDetails* device_details, const bool result) { 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(device_details); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result) 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const StorageObjects& storage_objects = device_details->storage_objects; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& name = device_details->name; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& location = device_details->location; 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!ContainsKey(device_map_, location)); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (StorageObjects::const_iterator storage_iter = storage_objects.begin(); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_iter != storage_objects.end(); ++storage_iter) { 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& storage_id = storage_iter->object_persistent_id; 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!ContainsKey(storage_map_, storage_id)); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Keep track of storage id and storage name to see how often we receive 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // empty values. 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MediaStorageUtil::RecordDeviceInfoHistogram(false, storage_id, name); 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (storage_id.empty() || name.empty()) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Device can have several data partitions. Therefore, add the 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // partition identifier to the storage name. E.g.: "Nexus 7 (s10001)" 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 storage_name(name + L" (" + storage_iter->object_temporary_id + 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L')'); 625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) StorageInfo info(storage_id, storage_name, location, 626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16(), string16(), string16(), 0); 627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) storage_map_[storage_id] = info; 6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (storage_notifications_) { 62990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) info.set_location(GetStoragePathFromStorageId(storage_id)); 630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) storage_notifications_->ProcessAttach(info); 6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_map_[location] = storage_objects; 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PortableDeviceWatcherWin::HandleDeviceDetachEvent( 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& pnp_device_id) { 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MTPDeviceMap::iterator device_iter = device_map_.find(pnp_device_id); 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_iter == device_map_.end()) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const StorageObjects& storage_objects = device_iter->second; 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (StorageObjects::const_iterator storage_object_iter = 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_objects.begin(); storage_object_iter != storage_objects.end(); 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++storage_object_iter) { 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string storage_id = storage_object_iter->object_persistent_id; 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MTPStorageMap::iterator storage_map_iter = storage_map_.find(storage_id); 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(storage_map_iter != storage_map_.end()); 65090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (storage_notifications_) { 65190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) storage_notifications_->ProcessDetach( 65290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) storage_map_iter->second.device_id()); 65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_map_.erase(storage_map_iter); 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_map_.erase(device_iter); 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace chrome 660