diff options
author | reillyg <reillyg@chromium.org> | 2015-01-05 20:06:26 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-01-06 04:07:05 +0000 |
commit | ec1f1c7f010d38beabcbbc653e0df4b299133c7a (patch) | |
tree | c1cf31a586e5bcabfda58d5d1e19d51aa443587f /device/core | |
parent | f58a0ec56b77d86d206cd703efee94a7c6513aab (diff) | |
download | chromium_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.gn | 2 | ||||
-rw-r--r-- | device/core/core.gyp | 2 | ||||
-rw-r--r-- | device/core/device_monitor_win.cc | 160 | ||||
-rw-r--r-- | device/core/device_monitor_win.h | 44 |
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 |