summaryrefslogtreecommitdiffstats
path: root/device
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
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')
-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
-rw-r--r--device/hid/BUILD.gn1
-rw-r--r--device/hid/hid.gyp3
-rw-r--r--device/hid/hid_service.cc40
-rw-r--r--device/hid/hid_service.h4
-rw-r--r--device/hid/hid_service_win.cc64
-rw-r--r--device/hid/hid_service_win.h18
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);
};