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

Unified Diff: chrome/browser/system_monitor/portable_device_watcher_win.cc

Issue 11088012: [Win, MediaGallery] Enumerate and handle mtp device attach/detach events. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed StringPrintf() Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/system_monitor/portable_device_watcher_win.cc
diff --git a/chrome/browser/system_monitor/portable_device_watcher_win.cc b/chrome/browser/system_monitor/portable_device_watcher_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..af2a2cff0a25c191b0168c56a1734aab3f6154fa
--- /dev/null
+++ b/chrome/browser/system_monitor/portable_device_watcher_win.cc
@@ -0,0 +1,637 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/system_monitor/portable_device_watcher_win.h"
+
+#include <dbt.h>
+#include <portabledevice.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/string_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_comptr.h"
+#include "chrome/browser/system_monitor/media_storage_util.h"
+#include "chrome/browser/system_monitor/removable_device_constants.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+
+namespace chrome {
+
+namespace {
+
+// Name of the client application that communicates with the mtp device.
+const char16 kClientName[] = L"Chromium";
+
+// Name of the sequenced task runner.
+const char kMediaTaskRunnerName[] = "media-task-runner";
+
+// Returns true if |data| represents a class of portable devices.
+bool IsPortableDeviceStructure(LPARAM data) {
+ DEV_BROADCAST_HDR* broadcast_hdr =
+ reinterpret_cast<DEV_BROADCAST_HDR*>(data);
+ if (!broadcast_hdr ||
+ (broadcast_hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)) {
+ return false;
+ }
+
+ GUID guidDevInterface = GUID_NULL;
+ if (FAILED(CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface)))
+ return false;
+ DEV_BROADCAST_DEVICEINTERFACE* dev_interface =
+ reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data);
+ return (IsEqualGUID(dev_interface->dbcc_classguid, guidDevInterface) != 0);
+}
+
+// Returns the portable device plug and play device ID string.
+string16 GetPnpDeviceId(LPARAM data) {
+ DEV_BROADCAST_DEVICEINTERFACE* dev_interface =
+ reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data);
+ if (!dev_interface)
+ return string16();
+ DCHECK(IsStringASCII(dev_interface->dbcc_name));
+ return StringToLowerASCII(string16(dev_interface->dbcc_name));
+}
+
+// Gets the friendly name of the device specified by the |pnp_device_id|. On
+// success, returns true and fills in |name|.
+bool GetFriendlyName(const string16& pnp_device_id,
+ IPortableDeviceManager* device_manager,
+ string16* name) {
+ DWORD name_len = 0;
+ HRESULT hr = device_manager->GetDeviceFriendlyName(pnp_device_id.c_str(),
+ NULL, &name_len);
+ if (FAILED(hr))
+ return false;
+
+ string16 friendly_name;
+ hr = device_manager->GetDeviceFriendlyName(
+ pnp_device_id.c_str(), WriteInto(&friendly_name, name_len), &name_len);
+ if (FAILED(hr))
+ return false;
+
+ if (name)
+ *name = friendly_name;
+ return !friendly_name.empty();
+}
+
+// Gets the manufacturer name of the device specified by the |pnp_device_id|.
+// On success, returns true and fills in |name|.
+bool GetManufacturerName(const string16& pnp_device_id,
+ IPortableDeviceManager* device_manager,
+ string16* name) {
+ DWORD name_len = 0;
+ HRESULT hr = device_manager->GetDeviceManufacturer(pnp_device_id.c_str(),
+ NULL, &name_len);
+ if (FAILED(hr))
+ return false;
+
+ string16 manufacturer_name;
+ hr = device_manager->GetDeviceManufacturer(
+ pnp_device_id.c_str(), WriteInto(&manufacturer_name, name_len),
+ &name_len);
+ if (FAILED(hr))
+ return false;
+
+ if (name)
+ *name = manufacturer_name;
+ return !manufacturer_name.empty();
+}
+
+// Gets the description of the device specified by the |pnp_device_id|. On
+// success, returns true and fills in |name|.
+bool GetDeviceDescription(const string16& pnp_device_id,
+ IPortableDeviceManager* device_manager,
+ string16* name) {
+ DWORD desc_len = 0;
+ HRESULT hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(), NULL,
+ &desc_len);
+ if (FAILED(hr))
+ return false;
+
+ string16 description;
+ hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(),
+ WriteInto(&description, desc_len),
+ &desc_len);
+ if (FAILED(hr))
+ return false;
+ if (name)
+ *name = description;
+ return !description.empty();
+}
+
+// On success, returns true and updates |client_info| with a reference to an
+// IPortableDeviceValues interface that holds information about the
+// application that communicates with the device.
+bool GetClientInformation(
+ base::win::ScopedComPtr<IPortableDeviceValues>* client_info) {
+ HRESULT hr = client_info->CreateInstance(__uuidof(PortableDeviceValues),
+ NULL, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to create an instance of IPortableDeviceValues";
+ return false;
+ }
+
+ // Attempt to set client details.
+ (*client_info)->SetStringValue(WPD_CLIENT_NAME, kClientName);
+
+ (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, 0);
+
+ (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, 0);
+
+ (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, 0);
+
+ (*client_info)->SetUnsignedIntegerValue(
+ WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION);
+
+ (*client_info)->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS,
+ GENERIC_READ);
+ return true;
+}
+
+// Opens the device for communication. |pnp_device_id| specifies the plug and
+// play device ID string. On success, returns true and updates |device| with a
+// reference to the portable device interface.
+bool Setup(const string16& pnp_device_id,
vandebo (ex-Chrome) 2012/10/25 19:24:47 nit: SetUp
kmadhusu 2012/10/26 02:01:24 Done.
+ base::win::ScopedComPtr<IPortableDevice>* device) {
+ base::win::ScopedComPtr<IPortableDeviceValues> client_info;
+ if (!GetClientInformation(&client_info))
+ return false;
+
+ HRESULT hr = device->CreateInstance(__uuidof(PortableDevice), NULL,
+ CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to create an instance of IPortableDevice";
+ return false;
+ }
+
+ hr = (*device)->Open(pnp_device_id.c_str(), client_info.get());
+ if (FAILED(hr)) {
+ if (hr == E_ACCESSDENIED)
+ DPLOG(ERROR) << "Access denied to open the device";
+ return false;
+ }
+ return true;
+}
+
+// Returns true if the object specified by the |object_id| is the device root
+// object.
+bool IsDeviceObjectId(const string16& object_id) {
vandebo (ex-Chrome) 2012/10/25 19:24:47 Used once (in a simple function), inline.
kmadhusu 2012/10/26 02:01:24 Done.
+ return (object_id == WPD_DEVICE_OBJECT_ID);
+}
+
+// Returns the unique id property key of the object specified by the
+// |object_id|.
+REFPROPERTYKEY GetUniqueIdPropertyKey(const string16& object_id) {
+ return IsDeviceObjectId(object_id) ?
+ WPD_DEVICE_SERIAL_NUMBER : WPD_OBJECT_PERSISTENT_UNIQUE_ID;
+}
+
+// On success, returns true and populates |properties_to_read| with the
+// property key of the object specified by the |object_id|.
+bool PopulatePropertyKeyCollection(
+ const string16& object_id,
+ base::win::ScopedComPtr<IPortableDeviceKeyCollection>* properties_to_read) {
+ HRESULT hr = properties_to_read->CreateInstance(
+ __uuidof(PortableDeviceKeyCollection), NULL, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to create IPortableDeviceKeyCollection instance";
+ return false;
+ }
+ REFPROPERTYKEY key = GetUniqueIdPropertyKey(object_id);
+ hr = (*properties_to_read)->Add(key);
+ return SUCCEEDED(hr);
+}
+
+// Wrapper function to get content property string value.
+bool GetStringPropertyValue(IPortableDeviceValues* properties_values,
+ REFPROPERTYKEY key,
+ string16* value) {
+ base::win::ScopedCoMem<char16> buffer;
+ HRESULT hr = properties_values->GetStringValue(key, &buffer);
+ if (FAILED(hr))
+ return false;
+
+ if (value)
+ *value = string16(buffer);
+ return true;
+}
+
+// Constructs a unique identifier for the object specified by the |object_id|.
+// On success, returns true and fills in |unique_id|.
+bool GetObjectUniqueId(IPortableDevice* device,
+ const string16& object_id,
+ string16* unique_id) {
+ base::win::ScopedComPtr<IPortableDeviceContent> content;
+ HRESULT hr = device->Content(content.Receive());
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to get IPortableDeviceContent interface";
+ return false;
+ }
+
+ base::win::ScopedComPtr<IPortableDeviceProperties> properties;
+ hr = content->Properties(properties.Receive());
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to get IPortableDeviceProperties interface";
+ return false;
+ }
+
+ base::win::ScopedComPtr<IPortableDeviceKeyCollection> properties_to_read;
+ if (!PopulatePropertyKeyCollection(object_id, &properties_to_read))
+ return false;
+
+ base::win::ScopedComPtr<IPortableDeviceValues> properties_values;
+ if (FAILED(properties->GetValues(object_id.c_str(),
+ properties_to_read.get(),
+ properties_values.Receive()))) {
+ return false;
+ }
+
+ REFPROPERTYKEY key = GetUniqueIdPropertyKey(object_id);
+ return GetStringPropertyValue(properties_values.get(), key, unique_id);
+}
+
+// Constructs the device storage unique identifier using |device_serial_num| and
+// |storage_id|. On success, returns true and fills in |device_storage_id|.
+bool GetDeviceStorageUniqueId(const string16& device_serial_num,
vandebo (ex-Chrome) 2012/10/25 19:24:47 nit: MakeDeviceStorageDeviceId or ConstructDeviceS
kmadhusu 2012/10/26 02:01:24 Renamed GetDeviceStorageUniqueId => ConstructDevic
+ const string16& storage_id,
+ std::string* device_storage_id) {
+ if (device_serial_num.empty() && storage_id.empty())
+ return false;
+
+ // |unique_id| format: StorageSerial:|storage_id|:|device_serial_num|
Peter Kasting 2012/10/25 05:23:24 Nit: Remove this comment, it just duplicates the c
kmadhusu 2012/10/26 02:01:24 Done.
+ string16 unique_id(chrome::kMtpDeviceStorageIdPrefix + storage_id +
+ UTF8ToUTF16(chrome::kNonSpaceDelim) + device_serial_num);
Peter Kasting 2012/10/25 05:23:24 First, use ASCIIToUTF16() when you know the input
kmadhusu 2012/10/26 02:01:24 Removed UTF..() function and used L':' directly.
+
+ // |device_storage_id| format: mtp:|unique_id|
+ *device_storage_id = MediaStorageUtil::MakeDeviceId(
+ MediaStorageUtil::MTP_OR_PTP, UTF16ToUTF8(unique_id));
+ return true;
+}
+
+// Gets a list of removable storage object identifiers present in |device|.
+// On success, returns true and fills in |storage_ids|.
+bool GetRemovableStorageObjectIds(IPortableDevice* device,
+ std::vector<string16>* storage_ids) {
+ base::win::ScopedComPtr<IPortableDeviceCapabilities> capabilities;
+ HRESULT hr = device->Capabilities(capabilities.Receive());
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to get IPortableDeviceCapabilities interface";
+ return false;
+ }
+
+ base::win::ScopedComPtr<IPortableDevicePropVariantCollection> storage_obj_ids;
+ hr = capabilities->GetFunctionalObjects(WPD_FUNCTIONAL_CATEGORY_STORAGE,
+ storage_obj_ids.Receive());
+ if (FAILED(hr)) {
+ DPLOG(ERROR) << "Failed to get IPortableDevicePropVariantCollection";
+ return false;
+ }
+
+ DWORD num_storage_obj_ids = 0;
+ hr = storage_obj_ids->GetCount(&num_storage_obj_ids);
+ if (FAILED(hr))
+ return false;
+
+ for (DWORD index = 0; index < num_storage_obj_ids; ++index) {
+ PROPVARIANT object_id = {0};
+ PropVariantInit(&object_id);
+ hr = storage_obj_ids->GetAt(index, &object_id);
+ if (SUCCEEDED(hr) && (object_id.pwszVal != NULL) &&
+ (object_id.vt == VT_LPWSTR)) {
+ storage_ids->push_back(object_id.pwszVal);
+ }
+ PropVariantClear(&object_id);
+ }
+ return true;
+}
+
+// Returns true if the portable device is mounted on a volume. |device_name|
+// specifies the name of the device.
+bool IsVolumeMountedPortableDevice(const string16& device_name) {
+ // If the device is a volume mounted device, |device_name| will be
+ // the volume name.
+ return (device_name.length() >= 2) && (device_name[1] == L':') &&
+ ((device_name[0] >= L'A') && (device_name[0] <= L'Z') ||
+ ((device_name[0] >= L'a') && (device_name[0] <= L'z')));
+}
+
+// Returns the name of the device specified by |pnp_device_id|.
+// Accessed on the blocking thread.
+string16 GetDeviceNameOnBlockingThread(
+ IPortableDeviceManager* portable_device_manager,
+ const string16& pnp_device_id) {
+ DCHECK(content::BrowserThread::
+ GetBlockingPool()->RunsTasksOnCurrentThread());
+ string16 name;
+ if (!(GetFriendlyName(pnp_device_id, portable_device_manager, &name) ||
+ GetDeviceDescription(pnp_device_id, portable_device_manager,
+ &name) ||
+ GetManufacturerName(pnp_device_id, portable_device_manager,
+ &name))) {
+ return string16();
+ }
+ return name;
+}
+
+// Gets the device storage details on the blocking thread. On success, returns
+// true and populates |storage_info_list| with device storage details.
+bool GetDeviceStorageInfoListOnBlockingThread(
+ const string16& pnp_device_id,
+ std::vector<PortableDeviceWatcherWin::DeviceStorageInfo>*
+ storage_info_list) {
+ DCHECK(content::BrowserThread::
+ GetBlockingPool()->RunsTasksOnCurrentThread());
+ base::win::ScopedComPtr<IPortableDevice> device;
+ if (!Setup(pnp_device_id, &device))
+ return false;
+
+ std::vector<string16> storage_obj_ids;
vandebo (ex-Chrome) 2012/10/25 19:24:47 Unless there's a reason to do this before getting
kmadhusu 2012/10/26 02:01:24 Done.
+ if (!GetRemovableStorageObjectIds(device.get(), &storage_obj_ids))
+ return false;
+
+ // Get the device serial number (E.g.: 4889033500677371).
+ string16 device_serial_num;
+ if (!GetObjectUniqueId(device.get(), WPD_DEVICE_OBJECT_ID,
+ &device_serial_num)) {
+ return false;
+ }
+
+ for (size_t index = 0; index < storage_obj_ids.size(); ++index) {
+ // Get the storage object persistent id (E.g.: SID-{10001,D,31080448}).
+ string16 storage_unique_id;
+ if (!GetObjectUniqueId(device.get(), storage_obj_ids[index],
vandebo (ex-Chrome) 2012/10/25 19:24:47 If you like, you could do: if (!GetObjectUniqueId
kmadhusu 2012/10/26 02:01:24 I would like to leave it as it is.
+ &storage_unique_id)) {
+ continue;
+ }
+ std::string device_storage_id;
+ if (GetDeviceStorageUniqueId(device_serial_num, storage_unique_id,
+ &device_storage_id)) {
+ PortableDeviceWatcherWin::DeviceStorageInfo storage_info;
+ storage_info.storage_object_id = storage_obj_ids[index];
+ storage_info.unique_id = device_storage_id;
+ storage_info_list->push_back(storage_info);
+ }
+ }
+ return true;
+}
+
+// Gets the device details (name, number of storages, etc.,) on the blocking
+// thread. |pnp_device_id| specifies the plug and play device ID string.
+PortableDeviceWatcherWin::DeviceDetails GetDeviceInfoOnBlockingThread(
+ IPortableDeviceManager* portable_device_manager,
+ const string16& pnp_device_id) {
+ DCHECK(content::BrowserThread::
+ GetBlockingPool()->RunsTasksOnCurrentThread());
+ DCHECK(!pnp_device_id.empty());
+ PortableDeviceWatcherWin::DeviceDetails device_details;
+ string16 device_name = GetDeviceNameOnBlockingThread(portable_device_manager,
+ pnp_device_id);
+ std::vector<PortableDeviceWatcherWin::DeviceStorageInfo> storage_info_list;
+ if (!GetDeviceStorageInfoListOnBlockingThread(pnp_device_id,
+ &storage_info_list)) {
+ return device_details;
+ }
+
+ if (IsVolumeMountedPortableDevice(device_name))
vandebo (ex-Chrome) 2012/10/25 19:24:47 Move above GetDeviceStorageInfoListOnBlockingThrea
kmadhusu 2012/10/26 02:01:24 Done.
+ return device_details;
+
+ device_details.storage_info_list = storage_info_list;
+ device_details.name = device_name;
+ device_details.location = pnp_device_id;
+ return device_details;
+}
+
+// Enumerates and returns a list of attached mtp device details on a
+// blocking thread.
+std::vector<PortableDeviceWatcherWin::DeviceDetails>
+EnumerateAttachedStoragesOnBlockingThread() {
+ DCHECK(content::BrowserThread::
+ GetBlockingPool()->RunsTasksOnCurrentThread());
+ std::vector<PortableDeviceWatcherWin::DeviceDetails> device_info_list;
+ base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr;
+ HRESULT hr = portable_device_mgr.CreateInstance(
+ __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ // Either there is no portable device support (it must be a XP with
+ // Windows Media Player Version < 10) or the thread does not have COM
+ // initialized.
+ DCHECK_NE(CO_E_NOTINITIALIZED, hr);
+ return device_info_list;
+ }
+
+ // Get the total number of devices found on the system.
+ DWORD pnp_device_count = 0;
+ hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count);
+ if (FAILED(hr))
+ return device_info_list;
+
+ scoped_array<LPWSTR> pnp_device_ids(new LPWSTR[pnp_device_count]);
+ ZeroMemory(pnp_device_ids.get(), pnp_device_count);
+ hr = portable_device_mgr->GetDevices(pnp_device_ids.get(), &pnp_device_count);
+ if (FAILED(hr))
+ return device_info_list;
+
+ for (DWORD index = 0; index < pnp_device_count; ++index) {
+ device_info_list.push_back(GetDeviceInfoOnBlockingThread(
+ portable_device_mgr, pnp_device_ids[index]));
+ }
+ return device_info_list;
+}
+
+// Handles the device attach event message on the blocking thread.
+// |pnp_device_id| specifies the attached plug and play device ID string.
+PortableDeviceWatcherWin::DeviceDetails
+HandleDeviceAttachedEventOnBlockingThread(const string16& pnp_device_id) {
+ DCHECK(content::BrowserThread::
+ GetBlockingPool()->RunsTasksOnCurrentThread());
+ PortableDeviceWatcherWin::DeviceDetails device_details;
+ base::win::ScopedComPtr<IPortableDeviceManager> portable_device_mgr;
+ HRESULT hr = portable_device_mgr.CreateInstance(
+ __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ // Either there is no portable device support (it must be a XP with
+ // Windows Media Player Version < 10) or the thread does not have COM
+ // initialized.
+ DCHECK_NE(CO_E_NOTINITIALIZED, hr);
+ return device_details;
vandebo (ex-Chrome) 2012/10/25 19:24:47 return PortabelDeviceWatcherWin::DeviceDetails() a
kmadhusu 2012/10/26 02:01:24 Modified the function to return void.
+ }
+ portable_device_mgr->RefreshDeviceList();
+ return GetDeviceInfoOnBlockingThread(portable_device_mgr, pnp_device_id);
+}
+
+// Constructs and returns a storage path from storage unique identifier.
+string16 GetStoragePathFromStorageId(const std::string& storage_unique_id) {
+ // Construct a dummy device path using the storage name. This is only used
+ // for registering device media file system.
+ DCHECK(!storage_unique_id.empty());
+ std::string root_path("\\\\");
vandebo (ex-Chrome) 2012/10/25 19:24:47 nit: const
kmadhusu 2012/10/26 02:01:24 Done.
+ return UTF8ToUTF16(root_path + storage_unique_id);
+}
+
+} // namespace
+
+PortableDeviceWatcherWin::PortableDeviceWatcherWin()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+ registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
+ content::NotificationService::AllSources());
+}
+
+PortableDeviceWatcherWin::~PortableDeviceWatcherWin() {
+}
+
+void PortableDeviceWatcherWin::Init() {
+ if (app_terminating_flag_.IsSet())
+ return;
+
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
+ base::SequencedWorkerPool::SequenceToken media_sequence_token =
+ pool->GetNamedSequenceToken(kMediaTaskRunnerName);
+ media_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ media_sequence_token, base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+ DCHECK(media_task_runner_.get());
+ EnumerateAttachedDevices();
+}
+
+bool PortableDeviceWatcherWin::GetDeviceInfo(const FilePath& device_path,
vandebo (ex-Chrome) 2012/10/25 19:24:47 Remove this method since it's not needed now and i
kmadhusu 2012/10/26 02:01:24 Done.
+ string16* location,
+ std::string* unique_id,
+ string16* name,
+ bool* removable) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void PortableDeviceWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (app_terminating_flag_.IsSet())
+ return;
+
+ switch (event_type) {
+ case DBT_DEVICEARRIVAL: {
+ if (IsPortableDeviceStructure(data))
+ HandleDeviceAttachEvent(GetPnpDeviceId(data));
+ break;
+ }
+ case DBT_DEVICEREMOVECOMPLETE: {
+ if (IsPortableDeviceStructure(data))
+ HandleDeviceDetachEvent(GetPnpDeviceId(data));
+ break;
+ }
+ }
+}
+
+void PortableDeviceWatcherWin::EnumerateAttachedDevices() {
+ DCHECK(media_task_runner_.get());
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (app_terminating_flag_.IsSet())
+ return;
+
+ base::PostTaskAndReplyWithResult(
+ media_task_runner_,
+ FROM_HERE,
+ base::Bind(&EnumerateAttachedStoragesOnBlockingThread),
+ base::Bind(&PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PortableDeviceWatcherWin::HandleDeviceAttachEvent(
+ const string16& pnp_device_id) {
+ DCHECK(media_task_runner_.get());
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (app_terminating_flag_.IsSet())
+ return;
+
+ base::PostTaskAndReplyWithResult(
+ media_task_runner_,
+ FROM_HERE,
+ base::Bind(&HandleDeviceAttachedEventOnBlockingThread, pnp_device_id),
+ base::Bind(&PortableDeviceWatcherWin::OnHandleDeviceAttachEvent,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PortableDeviceWatcherWin::HandleDeviceDetachEvent(
+ const string16& pnp_device_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ MtpDeviceMap::iterator device_entry = device_map_.find(pnp_device_id);
+ if (device_entry == device_map_.end())
+ return;
+
+ base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
+ DCHECK(system_monitor);
+
+ StorageInfoList storage_info_list = device_entry->second;
+ for (size_t index = 0; index < storage_info_list.size(); ++index) {
+ std::string storage_id = storage_info_list[index].unique_id;
+ MtpStorageMap::iterator storage_entry = storage_map_.find(storage_id);
+ DCHECK(storage_entry != storage_map_.end());
+ system_monitor->ProcessRemovableStorageDetached(
+ storage_entry->second.device_id);
+ storage_map_.erase(storage_entry);
+ }
+ device_map_.erase(device_entry);
+}
+
+void PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices(
+ std::vector<DeviceDetails> device_details_list) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ for (size_t index = 0; index < device_details_list.size(); ++index)
+ OnHandleDeviceAttachEvent(device_details_list[index]);
+}
+
+void PortableDeviceWatcherWin::OnHandleDeviceAttachEvent(
+ DeviceDetails device_details) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (app_terminating_flag_.IsSet())
+ return;
+
+ const StorageInfoList& storage_info_list = device_details.storage_info_list;
+ const string16& name = device_details.name;
+ const string16& location = device_details.location;
+ DCHECK(!ContainsKey(device_map_, location));
+ base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
+ DCHECK(system_monitor);
+ for (size_t index = 0; index < storage_info_list.size(); ++index) {
+ const std::string& storage_id = storage_info_list[index].unique_id;
+ DCHECK(!ContainsKey(storage_map_, storage_id));
+
+ // Keep track of storage id and storage name to see how often we receive
+ // empty values.
+ MediaStorageUtil::RecordDeviceInfoHistogram(false, storage_id, name);
+ if (storage_id.empty() || name.empty())
+ return;
+
+ // Device can have several data storage_info_list. Therefore, add the
+ // partition details to the storage name. E.g.: "Nexus 7 (s10001)"
+ string16 storage_name(name + UTF8ToUTF16(kSpaceDelim) +
+ UTF8ToUTF16(kLeftParen) +
+ storage_info_list[index].storage_object_id +
+ UTF8ToUTF16(kRightParen));
Peter Kasting 2012/10/25 05:23:24 See comments above regarding nuking these constant
kmadhusu 2012/10/26 02:01:24 Done.
+
+ base::SystemMonitor::RemovableStorageInfo storage_info(storage_id,
vandebo (ex-Chrome) 2012/10/25 19:24:47 nit: combine line 618 and 621
kmadhusu 2012/10/26 02:01:24 Done.
+ storage_name,
+ location);
+ storage_map_[storage_id] = storage_info;
+ system_monitor->ProcessRemovableStorageAttached(
+ storage_id, storage_name, GetStoragePathFromStorageId(storage_id));
+ }
+ device_map_[location] = storage_info_list;
+}
+
+void PortableDeviceWatcherWin::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
+ app_terminating_flag_.Set();
+}
+
+} // namespace chrome

Powered by Google App Engine
This is Rietveld 408576698