summaryrefslogtreecommitdiffstats
path: root/device/core
diff options
context:
space:
mode:
authorreillyg <reillyg@chromium.org>2015-01-05 20:06:26 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-06 04:07:05 +0000
commitec1f1c7f010d38beabcbbc653e0df4b299133c7a (patch)
treec1cf31a586e5bcabfda58d5d1e19d51aa443587f /device/core
parentf58a0ec56b77d86d206cd703efee94a7c6513aab (diff)
downloadchromium_src-ec1f1c7f010d38beabcbbc653e0df4b299133c7a.zip
chromium_src-ec1f1c7f010d38beabcbbc653e0df4b299133c7a.tar.gz
chromium_src-ec1f1c7f010d38beabcbbc653e0df4b299133c7a.tar.bz2
Create DeviceMonitorWin to manage device change notifications.
This change factors out the code in HidServiceWin that manages a MessageWindow for listening to device change notification messages. A single window is created for all registered device interfaces and consumers can use a simple observer interface to subscribe. The HidService is now destroyed using AtExitManager so that the two singletons are destroyed in the opposite of the order of their construction. BUG=411715 Review URL: https://codereview.chromium.org/818353002 Cr-Commit-Position: refs/heads/master@{#310046}
Diffstat (limited to 'device/core')
-rw-r--r--device/core/BUILD.gn2
-rw-r--r--device/core/core.gyp2
-rw-r--r--device/core/device_monitor_win.cc160
-rw-r--r--device/core/device_monitor_win.h44
4 files changed, 208 insertions, 0 deletions
diff --git a/device/core/BUILD.gn b/device/core/BUILD.gn
index 7d1671f..eefca3b 100644
--- a/device/core/BUILD.gn
+++ b/device/core/BUILD.gn
@@ -6,5 +6,7 @@ source_set("core") {
sources = [
"device_client.cc",
"device_client.h",
+ "device_monitor_win.cc",
+ "device_monitor_win.h",
]
}
diff --git a/device/core/core.gyp b/device/core/core.gyp
index 09bd315..3137de5 100644
--- a/device/core/core.gyp
+++ b/device/core/core.gyp
@@ -16,6 +16,8 @@
'sources': [
'device_client.cc',
'device_client.h',
+ 'device_monitor_win.cc',
+ 'device_monitor_win.h',
],
},
],
diff --git a/device/core/device_monitor_win.cc b/device/core/device_monitor_win.cc
new file mode 100644
index 0000000..0c81751
--- /dev/null
+++ b/device/core/device_monitor_win.cc
@@ -0,0 +1,160 @@
+// Copyright 2014 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 "device/core/device_monitor_win.h"
+
+#include <dbt.h>
+#include <map>
+#include <windows.h>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/win/message_window.h"
+
+namespace device {
+
+class DeviceMonitorMessageWindow;
+
+namespace {
+
+const wchar_t kWindowClassName[] = L"DeviceMonitorMessageWindow";
+DeviceMonitorMessageWindow* g_message_window;
+
+// Provides basic comparability for GUIDs so that they can be used as keys to an
+// STL map.
+struct CompareGUID {
+ bool operator()(const GUID& a, const GUID& b) {
+ return memcmp(&a, &b, sizeof a) < 0;
+ }
+};
+}
+
+// This singleton class manages a shared message window for all registered
+// device notification observers. It vends one instance of DeviceManagerWin for
+// each unique GUID it sees.
+class DeviceMonitorMessageWindow {
+ public:
+ static DeviceMonitorMessageWindow* GetInstance() {
+ if (!g_message_window) {
+ g_message_window = new DeviceMonitorMessageWindow();
+ base::AtExitManager::RegisterTask(
+ base::Bind(&base::DeletePointer<DeviceMonitorMessageWindow>,
+ base::Unretained(g_message_window)));
+ }
+ return g_message_window;
+ }
+
+ DeviceMonitorWin* GetForDeviceInterface(const GUID& device_interface) {
+ scoped_ptr<DeviceMonitorWin>& device_monitor =
+ device_monitors_[device_interface];
+ if (!device_monitor) {
+ DEV_BROADCAST_DEVICEINTERFACE db = {sizeof(DEV_BROADCAST_DEVICEINTERFACE),
+ DBT_DEVTYP_DEVICEINTERFACE,
+ 0,
+ device_interface};
+ HDEVNOTIFY notify_handle = RegisterDeviceNotification(
+ window_->hwnd(), &db, DEVICE_NOTIFY_WINDOW_HANDLE);
+ if (!notify_handle) {
+ LOG(ERROR) << "Failed to register for device notifications.";
+ return nullptr;
+ }
+ device_monitor.reset(new DeviceMonitorWin(notify_handle));
+ }
+ return device_monitor.get();
+ }
+
+ private:
+ friend void base::DeletePointer<DeviceMonitorMessageWindow>(
+ DeviceMonitorMessageWindow* message_window);
+
+ DeviceMonitorMessageWindow() {
+ window_.reset(new base::win::MessageWindow());
+ if (!window_->CreateNamed(
+ base::Bind(&DeviceMonitorMessageWindow::HandleMessage,
+ base::Unretained(this)),
+ base::string16(kWindowClassName))) {
+ LOG(ERROR) << "Failed to create message window: " << kWindowClassName;
+ window_.reset();
+ }
+ }
+
+ ~DeviceMonitorMessageWindow() {}
+
+ bool HandleMessage(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ LRESULT* result) {
+ if (message == WM_DEVICECHANGE) {
+ DEV_BROADCAST_DEVICEINTERFACE* db =
+ reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lparam);
+ const auto& map_entry = device_monitors_.find(db->dbcc_classguid);
+ if (map_entry == device_monitors_.end()) {
+ return false;
+ }
+ DeviceMonitorWin* device_monitor = map_entry->second.get();
+
+ std::string device_path(base::SysWideToUTF8(db->dbcc_name));
+ DCHECK(base::IsStringASCII(device_path));
+ if (wparam == DBT_DEVICEARRIVAL) {
+ device_monitor->NotifyDeviceAdded(
+ base::StringToLowerASCII(device_path));
+ } else if (wparam == DBT_DEVICEREMOVECOMPLETE) {
+ device_monitor->NotifyDeviceRemoved(
+ base::StringToLowerASCII(device_path));
+ } else {
+ return false;
+ }
+ *result = NULL;
+ return true;
+ }
+ return false;
+ }
+
+ std::map<GUID, scoped_ptr<DeviceMonitorWin>, CompareGUID> device_monitors_;
+ scoped_ptr<base::win::MessageWindow> window_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMessageWindow);
+};
+
+void DeviceMonitorWin::Observer::OnDeviceAdded(const std::string& device_path) {
+}
+
+void DeviceMonitorWin::Observer::OnDeviceRemoved(
+ const std::string& device_path) {
+}
+
+// static
+DeviceMonitorWin* DeviceMonitorWin::GetForDeviceInterface(
+ const GUID& device_interface) {
+ DeviceMonitorMessageWindow* message_window =
+ DeviceMonitorMessageWindow::GetInstance();
+ return message_window->GetForDeviceInterface(device_interface);
+}
+
+DeviceMonitorWin::~DeviceMonitorWin() {
+ UnregisterDeviceNotification(notify_handle_);
+}
+
+void DeviceMonitorWin::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void DeviceMonitorWin::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+DeviceMonitorWin::DeviceMonitorWin(HDEVNOTIFY notify_handle)
+ : notify_handle_(notify_handle) {
+}
+
+void DeviceMonitorWin::NotifyDeviceAdded(const std::string& device_path) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device_path));
+}
+
+void DeviceMonitorWin::NotifyDeviceRemoved(const std::string& device_path) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(device_path));
+}
+} \ No newline at end of file
diff --git a/device/core/device_monitor_win.h b/device/core/device_monitor_win.h
new file mode 100644
index 0000000..57a502f
--- /dev/null
+++ b/device/core/device_monitor_win.h
@@ -0,0 +1,44 @@
+// Copyright 2014 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.
+
+#ifndef DEVICE_CORE_DEVICE_MONITOR_WIN_H_
+#define DEVICE_CORE_DEVICE_MONITOR_WIN_H_
+
+#include <windows.h>
+
+#include "base/observer_list.h"
+
+namespace device {
+
+// Use an instance of this class to observe devices being added and removed
+// from the system, matched by device interface GUID.
+class DeviceMonitorWin {
+ public:
+ class Observer {
+ public:
+ virtual void OnDeviceAdded(const std::string& device_path);
+ virtual void OnDeviceRemoved(const std::string& device_path);
+ };
+
+ ~DeviceMonitorWin();
+
+ static DeviceMonitorWin* GetForDeviceInterface(const GUID& guid);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ private:
+ friend class DeviceMonitorMessageWindow;
+
+ DeviceMonitorWin(HDEVNOTIFY notify_handle);
+
+ void NotifyDeviceAdded(const std::string& device_path);
+ void NotifyDeviceRemoved(const std::string& device_path);
+
+ ObserverList<Observer> observer_list_;
+ HDEVNOTIFY notify_handle_;
+};
+}
+
+#endif // DEVICE_CORE_DEVICE_MONITOR_WIN_H_ \ No newline at end of file