Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Side by Side Diff: third_party/WebKit/Source/modules/webusb/USB.cpp

Issue 1850023002: Consume Mojo services directly in Blink's WebUSB implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Don't do assignments in if statements. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/webusb/USB.h" 5 #include "modules/webusb/USB.h"
6 6
7 #include "bindings/core/v8/CallbackPromiseAdapter.h"
8 #include "bindings/core/v8/ScriptPromise.h" 7 #include "bindings/core/v8/ScriptPromise.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h" 8 #include "bindings/core/v8/ScriptPromiseResolver.h"
10 #include "core/dom/DOMException.h" 9 #include "core/dom/DOMException.h"
11 #include "core/dom/Document.h" 10 #include "core/dom/Document.h"
12 #include "core/dom/ExceptionCode.h" 11 #include "core/dom/ExceptionCode.h"
12 #include "device/usb/public/interfaces/device.mojom-wtf.h"
13 #include "modules/EventTargetModules.h" 13 #include "modules/EventTargetModules.h"
14 #include "modules/webusb/USBConnectionEvent.h" 14 #include "modules/webusb/USBConnectionEvent.h"
15 #include "modules/webusb/USBController.h"
16 #include "modules/webusb/USBDevice.h" 15 #include "modules/webusb/USBDevice.h"
17 #include "modules/webusb/USBDeviceFilter.h" 16 #include "modules/webusb/USBDeviceFilter.h"
18 #include "modules/webusb/USBDeviceRequestOptions.h" 17 #include "modules/webusb/USBDeviceRequestOptions.h"
19 #include "modules/webusb/USBError.h" 18 #include "platform/MojoHelper.h"
20 #include "platform/UserGestureIndicator.h" 19 #include "platform/UserGestureIndicator.h"
21 #include "public/platform/Platform.h" 20 #include "public/platform/ServiceRegistry.h"
22 #include "public/platform/WebVector.h" 21 #include "wtf/Functional.h"
23 #include "public/platform/modules/webusb/WebUSBClient.h" 22
24 #include "public/platform/modules/webusb/WebUSBDeviceFilter.h" 23 namespace usb = device::usb::wtf;
25 #include "public/platform/modules/webusb/WebUSBDeviceRequestOptions.h"
26 #include "public/platform/modules/webusb/WebUSBError.h"
27 24
28 namespace blink { 25 namespace blink {
29 namespace { 26 namespace {
30 27
31 void convertDeviceFilter(const USBDeviceFilter& filter, WebUSBDeviceFilter* webF ilter) 28 const char kNoServiceError[] = "USB service unavailable.";
29
30 usb::DeviceFilterPtr convertDeviceFilter(const USBDeviceFilter& filter)
32 { 31 {
33 webFilter->hasVendorID = filter.hasVendorId(); 32 auto mojoFilter = usb::DeviceFilter::New();
34 if (filter.hasVendorId()) 33 mojoFilter->has_vendor_id = filter.hasVendorId();
35 webFilter->vendorID = filter.vendorId(); 34 if (mojoFilter->has_vendor_id)
36 webFilter->hasProductID = filter.hasProductId(); 35 mojoFilter->vendor_id = filter.vendorId();
37 if (filter.hasProductId()) 36 mojoFilter->has_product_id = filter.hasProductId();
38 webFilter->productID = filter.productId(); 37 if (mojoFilter->has_product_id)
39 webFilter->hasClassCode = filter.hasClassCode(); 38 mojoFilter->product_id = filter.productId();
40 if (filter.hasClassCode()) 39 mojoFilter->has_class_code = filter.hasClassCode();
41 webFilter->classCode = filter.classCode(); 40 if (mojoFilter->has_class_code)
42 webFilter->hasSubclassCode = filter.hasSubclassCode(); 41 mojoFilter->class_code = filter.classCode();
43 if (filter.hasSubclassCode()) 42 mojoFilter->has_subclass_code = filter.hasSubclassCode();
44 webFilter->subclassCode = filter.subclassCode(); 43 if (mojoFilter->has_subclass_code)
45 webFilter->hasProtocolCode = filter.hasProtocolCode(); 44 mojoFilter->subclass_code = filter.subclassCode();
46 if (filter.hasProtocolCode()) 45 mojoFilter->has_protocol_code = filter.hasProtocolCode();
47 webFilter->protocolCode = filter.protocolCode(); 46 if (mojoFilter->has_protocol_code)
47 mojoFilter->protocol_code = filter.protocolCode();
48 return mojoFilter;
48 } 49 }
49 50
50 void convertDeviceRequestOptions(const USBDeviceRequestOptions& options, WebUSBD eviceRequestOptions* webOptions) 51 bool isActive(ScriptPromiseResolver* resolver)
51 { 52 {
52 DCHECK(options.hasFilters()); 53 ExecutionContext* context = resolver->getExecutionContext();
53 webOptions->filters = WebVector<WebUSBDeviceFilter>(options.filters().size() ); 54 return context && !context->activeDOMObjectsAreStopped();
54 for (size_t i = 0; i < options.filters().size(); ++i) {
55 convertDeviceFilter(options.filters()[i], &webOptions->filters[i]);
56 }
57 } 55 }
58 56
59 // Allows using a CallbackPromiseAdapter with a WebVector to resolve the
60 // getDevices() promise with a HeapVector owning USBDevices.
61 class DeviceArray {
62 STATIC_ONLY(DeviceArray);
63 public:
64 using WebType = OwnPtr<WebVector<WebUSBDevice*>>;
65
66 static HeapVector<Member<USBDevice>> take(ScriptPromiseResolver* resolver, P assOwnPtr<WebVector<WebUSBDevice*>> webDevices)
67 {
68 HeapVector<Member<USBDevice>> devices;
69 for (const auto webDevice : *webDevices)
70 devices.append(USBDevice::create(adoptPtr(webDevice), resolver->getE xecutionContext()));
71 return devices;
72 }
73 };
74
75 } // namespace 57 } // namespace
76 58
77 USB::USB(LocalFrame& frame) 59 USB::USB(LocalFrame& frame)
78 : ContextLifecycleObserver(frame.document()) 60 : ContextLifecycleObserver(frame.document())
79 , m_client(USBController::from(frame).client())
80 { 61 {
81 ThreadState::current()->registerPreFinalizer(this); 62 frame.serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_deviceMana ger));
82 if (m_client) 63 m_deviceManager.set_connection_error_handler([this]() {
83 m_client->addObserver(this); 64 m_deviceManager.reset();
65 for (ScriptPromiseResolver* resolver : m_deviceManagerRequests) {
66 if (isActive(resolver))
67 resolver->reject(DOMException::create(NotFoundError, kNoServiceE rror));
68 }
69 m_deviceManagerRequests.clear();
70 });
71 // Set up two sequential calls to GetDeviceChanges to avoid latency.
72 m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeN otificationPtr>(&USB::onDeviceChanges, this)));
73 m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeN otificationPtr>(&USB::onDeviceChanges, this)));
84 } 74 }
85 75
86 USB::~USB() 76 USB::~USB()
87 { 77 {
88 } 78 DCHECK(!m_deviceManager);
89 79 DCHECK(m_deviceManagerRequests.isEmpty());
90 void USB::dispose() 80 DCHECK(!m_chooserService);
91 { 81 DCHECK(m_chooserServiceRequests.isEmpty());
92 // Promptly clears a raw reference from content/ to an on-heap object
93 // so that content/ doesn't access it in a lazy sweeping phase.
94 if (m_client)
95 m_client->removeObserver(this);
96 m_client = nullptr;
97 } 82 }
98 83
99 ScriptPromise USB::getDevices(ScriptState* scriptState) 84 ScriptPromise USB::getDevices(ScriptState* scriptState)
100 { 85 {
101 if (!m_client)
102 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(NotSupportedError));
103
104 String errorMessage;
105 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage))
106 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(SecurityError, errorMessage));
107
108 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 86 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
109 ScriptPromise promise = resolver->promise(); 87 ScriptPromise promise = resolver->promise();
110 m_client->getDevices(new CallbackPromiseAdapter<DeviceArray, USBError>(resol ver)); 88 if (!m_deviceManager) {
111 89 resolver->reject(DOMException::create(NotSupportedError));
90 } else {
91 String errorMessage;
92 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
93 resolver->reject(DOMException::create(SecurityError, errorMessage));
94 } else {
95 m_deviceManagerRequests.add(resolver);
96 m_deviceManager->GetDevices(nullptr, createBaseCallback(bind<mojo::W TFArray<usb::DeviceInfoPtr>>(&USB::onGetDevices, this, resolver)));
97 }
98 }
112 return promise; 99 return promise;
113 } 100 }
114 101
115 ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceReques tOptions& options) 102 ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceReques tOptions& options)
116 { 103 {
117 if (!m_client)
118 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(NotSupportedError));
119
120 String errorMessage;
121 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage))
122 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(SecurityError, errorMessage));
123
124 if (!UserGestureIndicator::consumeUserGesture())
125 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(SecurityError, "Must be handling a user gesture to show a permission requ est."));
126
127 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 104 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
128 ScriptPromise promise = resolver->promise(); 105 ScriptPromise promise = resolver->promise();
129 106
130 WebUSBDeviceRequestOptions webOptions; 107 if (!m_chooserService) {
131 convertDeviceRequestOptions(options, &webOptions); 108 LocalFrame* frame = getExecutionContext() ? toDocument(getExecutionConte xt())->frame() : nullptr;
132 m_client->requestDevice(webOptions, new CallbackPromiseAdapter<USBDevice, US BError>(resolver)); 109 if (!frame) {
110 resolver->reject(DOMException::create(NotSupportedError));
111 return promise;
112 }
113 frame->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_choos erService));
114 m_chooserService.set_connection_error_handler([this]() {
115 m_chooserService.reset();
116 for (ScriptPromiseResolver* resolver : m_chooserServiceRequests) {
117 if (isActive(resolver))
118 resolver->reject(DOMException::create(NotFoundError, kNoServ iceError));
119 }
120 m_chooserServiceRequests.clear();
121 });
122 }
133 123
124 String errorMessage;
125 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
126 resolver->reject(DOMException::create(SecurityError, errorMessage));
127 } else if (!UserGestureIndicator::consumeUserGesture()) {
128 resolver->reject(DOMException::create(SecurityError, "Must be handling a user gesture to show a permission request."));
129 } else {
130 Vector<usb::DeviceFilterPtr> filters;
131 if (options.hasFilters()) {
132 filters.reserveCapacity(options.filters().size());
133 for (const auto& filter : options.filters())
134 filters.append(convertDeviceFilter(filter));
135 }
136 m_chooserServiceRequests.add(resolver);
137 m_chooserService->GetPermission(std::move(filters), createBaseCallback(b ind<usb::DeviceInfoPtr>(&USB::onGetPermission, this, resolver)));
138 }
134 return promise; 139 return promise;
135 } 140 }
136 141
137 ExecutionContext* USB::getExecutionContext() const 142 ExecutionContext* USB::getExecutionContext() const
138 { 143 {
139 return ContextLifecycleObserver::getExecutionContext(); 144 return ContextLifecycleObserver::getExecutionContext();
140 } 145 }
141 146
142 const AtomicString& USB::interfaceName() const 147 const AtomicString& USB::interfaceName() const
143 { 148 {
144 return EventTargetNames::USB; 149 return EventTargetNames::USB;
145 } 150 }
146 151
147 void USB::contextDestroyed() 152 void USB::contextDestroyed()
148 { 153 {
149 if (m_client) 154 m_deviceManager.reset();
150 m_client->removeObserver(this); 155 m_deviceManagerRequests.clear();
151 m_client = nullptr; 156 m_chooserService.reset();
157 m_chooserServiceRequests.clear();
152 } 158 }
153 159
154 void USB::onDeviceConnected(std::unique_ptr<WebUSBDevice> device) 160 void USB::onGetDevices(ScriptPromiseResolver* resolver, mojo::WTFArray<usb::Devi ceInfoPtr> deviceInfos)
155 { 161 {
156 dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice: :create(adoptPtr(device.release()), getExecutionContext()))); 162 if (!isActive(resolver))
163 return;
164
165 HeapVector<Member<USBDevice>> devices;
166 for (auto& deviceInfo : deviceInfos.PassStorage()) {
167 usb::DevicePtr device;
168 m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
169 devices.append(USBDevice::create(std::move(deviceInfo), std::move(device ), resolver->getExecutionContext()));
170 }
171 resolver->resolve(devices);
172 m_deviceManagerRequests.remove(resolver);
157 } 173 }
158 174
159 void USB::onDeviceDisconnected(std::unique_ptr<WebUSBDevice> device) 175 void USB::onGetPermission(ScriptPromiseResolver* resolver, usb::DeviceInfoPtr de viceInfo)
160 { 176 {
161 dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevi ce::create(adoptPtr(device.release()), getExecutionContext()))); 177 if (!isActive(resolver))
178 return;
179
180 if (deviceInfo) {
181 usb::DevicePtr device;
182 m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
183 resolver->resolve(USBDevice::create(std::move(deviceInfo), std::move(dev ice), resolver->getExecutionContext()));
184 } else {
185 resolver->reject(DOMException::create(NotFoundError, "No device selected ."));
186 }
187 }
188
189 void USB::onDeviceChanges(usb::DeviceChangeNotificationPtr notification)
190 {
191 m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeN otificationPtr>(&USB::onDeviceChanges, this)));
192 for (auto& deviceInfo : notification->devices_added.PassStorage()) {
193 usb::DevicePtr device;
194 m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
195 dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDev ice::create(std::move(deviceInfo), std::move(device), getExecutionContext())));
196 }
197 for (auto& deviceInfo : notification->devices_removed.PassStorage())
198 dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USB Device::create(std::move(deviceInfo), nullptr, getExecutionContext())));
162 } 199 }
163 200
164 DEFINE_TRACE(USB) 201 DEFINE_TRACE(USB)
165 { 202 {
166 EventTargetWithInlineData::trace(visitor); 203 EventTargetWithInlineData::trace(visitor);
167 ContextLifecycleObserver::trace(visitor); 204 ContextLifecycleObserver::trace(visitor);
205 visitor->trace(m_deviceManagerRequests);
206 visitor->trace(m_chooserServiceRequests);
168 } 207 }
169 208
170 } // namespace blink 209 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/modules/webusb/USB.h ('k') | third_party/WebKit/Source/modules/webusb/USBAlternateInterface.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698