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 | |
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')
-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 | ||||
-rw-r--r-- | device/hid/BUILD.gn | 1 | ||||
-rw-r--r-- | device/hid/hid.gyp | 3 | ||||
-rw-r--r-- | device/hid/hid_service.cc | 40 | ||||
-rw-r--r-- | device/hid/hid_service.h | 4 | ||||
-rw-r--r-- | device/hid/hid_service_win.cc | 64 | ||||
-rw-r--r-- | device/hid/hid_service_win.h | 18 |
10 files changed, 242 insertions, 96 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 diff --git a/device/hid/BUILD.gn b/device/hid/BUILD.gn index 6197cf4..8616273 100644 --- a/device/hid/BUILD.gn +++ b/device/hid/BUILD.gn @@ -40,6 +40,7 @@ source_set("hid") { deps = [ "//base", + "//device/core", "//net", ] diff --git a/device/hid/hid.gyp b/device/hid/hid.gyp index 1c01ca1..f679c5c 100644 --- a/device/hid/hid.gyp +++ b/device/hid/hid.gyp @@ -13,6 +13,9 @@ 'include_dirs': [ '../..', ], + 'dependencies': [ + '../core/core.gyp:device_core', + ], 'sources': [ 'device_monitor_linux.cc', 'device_monitor_linux.h', diff --git a/device/hid/hid_service.cc b/device/hid/hid_service.cc index f78bccd..4953f25 100644 --- a/device/hid/hid_service.cc +++ b/device/hid/hid_service.cc @@ -4,6 +4,7 @@ #include "device/hid/hid_service.h" +#include "base/at_exit.h" #include "base/bind.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" @@ -21,27 +22,8 @@ namespace device { namespace { -HidService* g_service = NULL; - -} // namespace - -class HidService::Destroyer : public base::MessageLoop::DestructionObserver { - public: - explicit Destroyer(HidService* hid_service) - : hid_service_(hid_service) {} - ~Destroyer() override {} - - private: - // base::MessageLoop::DestructionObserver implementation. - void WillDestroyCurrentMessageLoop() override { - base::MessageLoop::current()->RemoveDestructionObserver(this); - delete hid_service_; - delete this; - g_service = NULL; - } - - HidService* hid_service_; -}; +HidService* g_service; +} HidService* HidService::GetInstance( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) { @@ -54,8 +36,8 @@ HidService* HidService::GetInstance( g_service = new HidServiceWin(); #endif if (g_service != nullptr) { - Destroyer* destroyer = new Destroyer(g_service); - base::MessageLoop::current()->AddDestructionObserver(destroyer); + base::AtExitManager::RegisterTask(base::Bind( + &base::DeletePointer<HidService>, base::Unretained(g_service))); } } return g_service; @@ -64,12 +46,8 @@ HidService* HidService::GetInstance( void HidService::SetInstanceForTest(HidService* instance) { DCHECK(!g_service); g_service = instance; - Destroyer* destroyer = new Destroyer(g_service); - base::MessageLoop::current()->AddDestructionObserver(destroyer); -} - -HidService::~HidService() { - DCHECK(thread_checker_.CalledOnValidThread()); + base::AtExitManager::RegisterTask(base::Bind(&base::DeletePointer<HidService>, + base::Unretained(g_service))); } void HidService::GetDevices(const GetDevicesCallback& callback) { @@ -108,6 +86,10 @@ bool HidService::GetDeviceInfo(const HidDeviceId& device_id, HidService::HidService() : enumeration_ready_(false) { } +HidService::~HidService() { + DCHECK(thread_checker_.CalledOnValidThread()); +} + void HidService::AddDevice(const HidDeviceInfo& info) { DCHECK(thread_checker_.CalledOnValidThread()); if (!ContainsKey(devices_, info.device_id)) { diff --git a/device/hid/hid_service.h b/device/hid/hid_service.h index 6c5c5a6..8d296c0 100644 --- a/device/hid/hid_service.h +++ b/device/hid/hid_service.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/bind_helpers.h" #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/single_thread_task_runner.h" @@ -59,6 +60,7 @@ class HidService { const ConnectCallback& callback) = 0; protected: + friend void base::DeletePointer<HidService>(HidService* service); friend class HidConnectionTest; typedef std::map<HidDeviceId, HidDeviceInfo> DeviceMap; @@ -75,8 +77,6 @@ class HidService { base::ThreadChecker thread_checker_; private: - class Destroyer; - DeviceMap devices_; bool enumeration_ready_; std::vector<GetDevicesCallback> pending_enumerations_; diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc index 58a40b3..e497837 100644 --- a/device/hid/hid_service_win.cc +++ b/device/hid/hid_service_win.cc @@ -18,7 +18,6 @@ #include "base/strings/sys_string_conversions.h" #include "base/thread_task_runner_handle.h" #include "base/threading/thread_restrictions.h" -#include "base/win/message_window.h" #include "device/hid/hid_connection_win.h" #include "device/hid/hid_device_info.h" #include "net/base/io_buffer.h" @@ -28,17 +27,15 @@ #pragma comment(lib, "hid.lib") namespace device { -namespace { -const char kHIDClass[] = "HIDClass"; -const wchar_t kWindowClassName[] = L"HidServiceMessageWindow"; - -} // namespace - -HidServiceWin::HidServiceWin() { +HidServiceWin::HidServiceWin() : device_observer_(this) { task_runner_ = base::ThreadTaskRunnerHandle::Get(); DCHECK(task_runner_.get()); - RegisterForDeviceNotifications(); + DeviceMonitorWin* device_monitor = + DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_HID); + if (device_monitor) { + device_observer_.Add(device_monitor); + } DoInitialEnumeration(); } @@ -65,49 +62,6 @@ void HidServiceWin::Connect(const HidDeviceId& device_id, } HidServiceWin::~HidServiceWin() { - if (notify_handle_) { - UnregisterDeviceNotification(notify_handle_); - } -} - -void HidServiceWin::RegisterForDeviceNotifications() { - window_.reset(new base::win::MessageWindow()); - if (!window_->CreateNamed( - base::Bind(&HidServiceWin::HandleMessage, base::Unretained(this)), - base::string16(kWindowClassName))) { - LOG(ERROR) << "Failed to create message window: " << kWindowClassName; - window_.reset(); - } - DEV_BROADCAST_DEVICEINTERFACE db = { sizeof(DEV_BROADCAST_DEVICEINTERFACE), - DBT_DEVTYP_DEVICEINTERFACE, - 0, - GUID_DEVINTERFACE_HID }; - notify_handle_ = RegisterDeviceNotification(window_->hwnd(), &db, - DEVICE_NOTIFY_WINDOW_HANDLE); - if (!notify_handle_) { - LOG(ERROR) << "Failed to register for device notifications."; - window_.reset(); - } -} - -bool HidServiceWin::HandleMessage(UINT message, - WPARAM wparam, - LPARAM lparam, - LRESULT* result) { - if (message == WM_DEVICECHANGE) { - DEV_BROADCAST_DEVICEINTERFACE* db = - reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lparam); - std::string device_path(base::SysWideToUTF8(db->dbcc_name)); - DCHECK(base::IsStringASCII(device_path)); - if (wparam == DBT_DEVICEARRIVAL) { - PlatformAddDevice(base::StringToLowerASCII(device_path)); - } else if (wparam == DBT_DEVICEREMOVECOMPLETE) { - PlatformRemoveDevice(base::StringToLowerASCII(device_path)); - } - *result = NULL; - return true; - } - return false; } void HidServiceWin::DoInitialEnumeration() { @@ -149,7 +103,7 @@ void HidServiceWin::DoInitialEnumeration() { std::string device_path( base::SysWideToUTF8(device_interface_detail_data->DevicePath)); DCHECK(base::IsStringASCII(device_path)); - PlatformAddDevice(device_path); + OnDeviceAdded(base::StringToLowerASCII(device_path)); } } @@ -201,7 +155,7 @@ void HidServiceWin::CollectInfoFromValueCaps( } } -void HidServiceWin::PlatformAddDevice(const std::string& device_path) { +void HidServiceWin::OnDeviceAdded(const std::string& device_path) { HidDeviceInfo device_info; device_info.device_id = device_path; @@ -282,7 +236,7 @@ void HidServiceWin::PlatformAddDevice(const std::string& device_path) { AddDevice(device_info); } -void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) { +void HidServiceWin::OnDeviceRemoved(const std::string& device_path) { RemoveDevice(device_path); } diff --git a/device/hid/hid_service_win.h b/device/hid/hid_service_win.h index 50f6353..902d431 100644 --- a/device/hid/hid_service_win.h +++ b/device/hid/hid_service_win.h @@ -14,7 +14,9 @@ extern "C" { } #include "base/memory/scoped_ptr.h" +#include "base/scoped_observer.h" #include "base/win/scoped_handle.h" +#include "device/core/device_monitor_win.h" #include "device/hid/hid_device_info.h" #include "device/hid/hid_service.h" @@ -26,7 +28,7 @@ class MessageWindow; namespace device { -class HidServiceWin : public HidService { +class HidServiceWin : public HidService, public DeviceMonitorWin::Observer { public: HidServiceWin(); @@ -36,11 +38,6 @@ class HidServiceWin : public HidService { private: virtual ~HidServiceWin(); - void RegisterForDeviceNotifications(); - bool HandleMessage(UINT message, - WPARAM wparam, - LPARAM lparam, - LRESULT* result); void DoInitialEnumeration(); static void CollectInfoFromButtonCaps(PHIDP_PREPARSED_DATA preparsed_data, HIDP_REPORT_TYPE report_type, @@ -50,15 +47,16 @@ class HidServiceWin : public HidService { HIDP_REPORT_TYPE report_type, USHORT value_caps_length, HidCollectionInfo* collection_info); - void PlatformAddDevice(const std::string& device_path); - void PlatformRemoveDevice(const std::string& device_path); + + // DeviceMonitorWin::Observer implementation: + void OnDeviceAdded(const std::string& device_path) override; + void OnDeviceRemoved(const std::string& device_path) override; // Tries to open the device read-write and falls back to read-only. base::win::ScopedHandle OpenDevice(const std::string& device_path); scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_ptr<base::win::MessageWindow> window_; - HDEVNOTIFY notify_handle_; + ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; DISALLOW_COPY_AND_ASSIGN(HidServiceWin); }; |