Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / device / core / device_monitor_win.cc
blob3449c82350e658b5b93379141946f63a8ce993cc
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
3 // found in the LICENSE file.
5 #include "device/core/device_monitor_win.h"
7 #include <dbt.h>
8 #include <map>
9 #include <windows.h>
11 #include "base/at_exit.h"
12 #include "base/bind.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "base/win/message_window.h"
17 namespace device {
19 class DeviceMonitorMessageWindow;
21 namespace {
23 const wchar_t kWindowClassName[] = L"DeviceMonitorMessageWindow";
24 DeviceMonitorMessageWindow* g_message_window;
26 // Provides basic comparability for GUIDs so that they can be used as keys to an
27 // STL map.
28 struct CompareGUID {
29 bool operator()(const GUID& a, const GUID& b) const {
30 return memcmp(&a, &b, sizeof a) < 0;
35 // This singleton class manages a shared message window for all registered
36 // device notification observers. It vends one instance of DeviceManagerWin for
37 // each unique GUID it sees.
38 class DeviceMonitorMessageWindow {
39 public:
40 static DeviceMonitorMessageWindow* GetInstance() {
41 if (!g_message_window) {
42 g_message_window = new DeviceMonitorMessageWindow();
43 if (g_message_window->Init()) {
44 base::AtExitManager::RegisterTask(
45 base::Bind(&base::DeletePointer<DeviceMonitorMessageWindow>,
46 base::Unretained(g_message_window)));
47 } else {
48 delete g_message_window;
49 g_message_window = nullptr;
52 return g_message_window;
55 DeviceMonitorWin* GetForDeviceInterface(const GUID& device_interface) {
56 scoped_ptr<DeviceMonitorWin>& device_monitor =
57 device_monitors_[device_interface];
58 if (!device_monitor) {
59 device_monitor.reset(new DeviceMonitorWin());
61 return device_monitor.get();
64 DeviceMonitorWin* GetForAllInterfaces() { return &all_device_monitor_; }
66 private:
67 friend void base::DeletePointer<DeviceMonitorMessageWindow>(
68 DeviceMonitorMessageWindow* message_window);
70 DeviceMonitorMessageWindow() {
73 ~DeviceMonitorMessageWindow() {
74 if (notify_handle_) {
75 UnregisterDeviceNotification(notify_handle_);
79 bool Init() {
80 window_.reset(new base::win::MessageWindow());
81 if (!window_->CreateNamed(
82 base::Bind(&DeviceMonitorMessageWindow::HandleMessage,
83 base::Unretained(this)),
84 base::string16(kWindowClassName))) {
85 LOG(ERROR) << "Failed to create message window: " << kWindowClassName;
86 return false;
89 DEV_BROADCAST_DEVICEINTERFACE db = {sizeof(DEV_BROADCAST_DEVICEINTERFACE),
90 DBT_DEVTYP_DEVICEINTERFACE};
91 notify_handle_ = RegisterDeviceNotification(
92 window_->hwnd(), &db,
93 DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
94 if (!notify_handle_) {
95 PLOG(ERROR) << "Failed to register for device notifications";
96 return false;
99 return true;
102 bool HandleMessage(UINT message,
103 WPARAM wparam,
104 LPARAM lparam,
105 LRESULT* result) {
106 if (message == WM_DEVICECHANGE) {
107 DeviceMonitorWin* device_monitor = nullptr;
108 DEV_BROADCAST_DEVICEINTERFACE* db =
109 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lparam);
110 const auto& map_entry = device_monitors_.find(db->dbcc_classguid);
111 if (map_entry != device_monitors_.end()) {
112 device_monitor = map_entry->second.get();
115 std::string device_path(base::SysWideToUTF8(db->dbcc_name));
116 DCHECK(base::IsStringASCII(device_path));
117 device_path = base::StringToLowerASCII(device_path);
119 if (wparam == DBT_DEVICEARRIVAL) {
120 if (device_monitor) {
121 device_monitor->NotifyDeviceAdded(db->dbcc_classguid, device_path);
123 all_device_monitor_.NotifyDeviceAdded(db->dbcc_classguid, device_path);
124 } else if (wparam == DBT_DEVICEREMOVECOMPLETE) {
125 if (device_monitor) {
126 device_monitor->NotifyDeviceRemoved(db->dbcc_classguid, device_path);
128 all_device_monitor_.NotifyDeviceRemoved(db->dbcc_classguid,
129 device_path);
130 } else {
131 return false;
133 *result = NULL;
134 return true;
136 return false;
139 std::map<GUID, scoped_ptr<DeviceMonitorWin>, CompareGUID> device_monitors_;
140 DeviceMonitorWin all_device_monitor_;
141 scoped_ptr<base::win::MessageWindow> window_;
142 HDEVNOTIFY notify_handle_ = NULL;
144 DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMessageWindow);
147 void DeviceMonitorWin::Observer::OnDeviceAdded(const GUID& class_guid,
148 const std::string& device_path) {
151 void DeviceMonitorWin::Observer::OnDeviceRemoved(
152 const GUID& class_guid,
153 const std::string& device_path) {
156 // static
157 DeviceMonitorWin* DeviceMonitorWin::GetForDeviceInterface(
158 const GUID& device_interface) {
159 DeviceMonitorMessageWindow* message_window =
160 DeviceMonitorMessageWindow::GetInstance();
161 if (message_window) {
162 return message_window->GetForDeviceInterface(device_interface);
164 return nullptr;
167 // static
168 DeviceMonitorWin* DeviceMonitorWin::GetForAllInterfaces() {
169 DeviceMonitorMessageWindow* message_window =
170 DeviceMonitorMessageWindow::GetInstance();
171 if (message_window) {
172 return message_window->GetForAllInterfaces();
174 return nullptr;
177 DeviceMonitorWin::~DeviceMonitorWin() {
180 void DeviceMonitorWin::AddObserver(Observer* observer) {
181 observer_list_.AddObserver(observer);
184 void DeviceMonitorWin::RemoveObserver(Observer* observer) {
185 observer_list_.RemoveObserver(observer);
188 DeviceMonitorWin::DeviceMonitorWin() {
191 void DeviceMonitorWin::NotifyDeviceAdded(const GUID& class_guid,
192 const std::string& device_path) {
193 FOR_EACH_OBSERVER(Observer, observer_list_,
194 OnDeviceAdded(class_guid, device_path));
197 void DeviceMonitorWin::NotifyDeviceRemoved(const GUID& class_guid,
198 const std::string& device_path) {
199 FOR_EACH_OBSERVER(Observer, observer_list_,
200 OnDeviceRemoved(class_guid, device_path));
203 } // namespace device