1 // Copyright 2015 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 "extensions/browser/api/usb/usb_event_router.h"
7 #include "device/core/device_client.h"
8 #include "device/usb/usb_device.h"
9 #include "device/usb/usb_service.h"
10 #include "extensions/browser/api/device_permissions_manager.h"
11 #include "extensions/common/api/usb.h"
12 #include "extensions/common/permissions/permissions_data.h"
13 #include "extensions/common/permissions/usb_device_permission.h"
15 namespace usb
= extensions::core_api::usb
;
17 using content::BrowserThread
;
18 using device::UsbDevice
;
19 using device::UsbService
;
21 namespace extensions
{
25 // Returns true iff the given extension has permission to receive events
26 // regarding this device.
27 bool WillDispatchDeviceEvent(scoped_refptr
<UsbDevice
> device
,
28 const base::string16
& serial_number
,
29 content::BrowserContext
* browser_context
,
30 const Extension
* extension
,
31 base::ListValue
* event_args
) {
32 // Check install-time and optional permissions.
33 UsbDevicePermission::CheckParam
param(
34 device
->vendor_id(), device
->product_id(),
35 UsbDevicePermissionData::UNSPECIFIED_INTERFACE
);
36 if (extension
->permissions_data()->CheckAPIPermissionWithParam(
37 APIPermission::kUsbDevice
, ¶m
)) {
41 // Check permissions granted through chrome.usb.getUserSelectedDevices.
42 scoped_ptr
<DevicePermissions
> device_permissions
=
43 DevicePermissionsManager::Get(browser_context
)
44 ->GetForExtension(extension
->id());
45 if (device_permissions
->FindEntry(device
, serial_number
).get()) {
52 base::LazyInstance
<BrowserContextKeyedAPIFactory
<UsbEventRouter
>>::Leaky
53 g_event_router_factory
= LAZY_INSTANCE_INITIALIZER
;
57 class UsbEventRouter::FileThreadHelper
: public UsbService::Observer
{
59 FileThreadHelper(base::WeakPtr
<UsbEventRouter
> usb_event_router
)
60 : usb_event_router_(usb_event_router
), observer_(this) {}
61 virtual ~FileThreadHelper() {}
64 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
65 UsbService
* service
= device::DeviceClient::Get()->GetUsbService();
67 observer_
.Add(service
);
72 // UsbService::Observer implementation.
73 void OnDeviceAdded(scoped_refptr
<device::UsbDevice
> device
) override
{
74 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
76 base::string16 serial_number
;
77 device
->GetSerialNumber(&serial_number
);
79 BrowserThread::PostTask(
80 BrowserThread::UI
, FROM_HERE
,
81 base::Bind(&UsbEventRouter::DispatchEvent
, usb_event_router_
,
82 usb::OnDeviceAdded::kEventName
, device
, serial_number
));
85 void OnDeviceRemoved(scoped_refptr
<device::UsbDevice
> device
) override
{
86 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
88 base::string16 serial_number
;
89 device
->GetSerialNumber(&serial_number
);
91 BrowserThread::PostTask(
92 BrowserThread::UI
, FROM_HERE
,
93 base::Bind(&UsbEventRouter::DispatchEvent
, usb_event_router_
,
94 usb::OnDeviceRemoved::kEventName
, device
, serial_number
));
97 base::WeakPtr
<UsbEventRouter
> usb_event_router_
;
98 ScopedObserver
<device::UsbService
, device::UsbService::Observer
> observer_
;
102 BrowserContextKeyedAPIFactory
<UsbEventRouter
>*
103 UsbEventRouter::GetFactoryInstance() {
104 return g_event_router_factory
.Pointer();
107 UsbEventRouter::UsbEventRouter(content::BrowserContext
* browser_context
)
108 : browser_context_(browser_context
), weak_factory_(this) {
109 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
111 event_router
->RegisterObserver(this, usb::OnDeviceAdded::kEventName
);
112 event_router
->RegisterObserver(this, usb::OnDeviceRemoved::kEventName
);
116 UsbEventRouter::~UsbEventRouter() {
119 void UsbEventRouter::Shutdown() {
120 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
122 event_router
->UnregisterObserver(this);
124 helper_
.reset(nullptr);
127 void UsbEventRouter::OnListenerAdded(const EventListenerInfo
& details
) {
129 helper_
.reset(new FileThreadHelper(weak_factory_
.GetWeakPtr()));
130 BrowserThread::PostTask(
131 BrowserThread::FILE, FROM_HERE
,
132 base::Bind(&FileThreadHelper::Start
, base::Unretained(helper_
.get())));
136 void UsbEventRouter::DispatchEvent(const std::string
& event_name
,
137 scoped_refptr
<UsbDevice
> device
,
138 const base::string16
& serial_number
) {
139 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
141 usb::Device device_obj
;
142 device_obj
.device
= device
->unique_id();
143 device_obj
.vendor_id
= device
->vendor_id();
144 device_obj
.product_id
= device
->product_id();
146 scoped_ptr
<Event
> event
;
147 if (event_name
== usb::OnDeviceAdded::kEventName
) {
148 event
.reset(new Event(usb::OnDeviceAdded::kEventName
,
149 usb::OnDeviceAdded::Create(device_obj
)));
151 DCHECK(event_name
== usb::OnDeviceRemoved::kEventName
);
152 event
.reset(new Event(usb::OnDeviceRemoved::kEventName
,
153 usb::OnDeviceRemoved::Create(device_obj
)));
156 event
->will_dispatch_callback
=
157 base::Bind(&WillDispatchDeviceEvent
, device
, serial_number
);
158 event_router
->BroadcastEvent(event
.Pass());