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

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: Remove promise adapters, use WTF::bind instead. 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-blink.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::blink;
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 if ((mojoFilter->has_vendor_id = filter.hasVendorId()))
35 webFilter->vendorID = filter.vendorId(); 34 mojoFilter->vendor_id = filter.vendorId();
36 webFilter->hasProductID = filter.hasProductId(); 35 if ((mojoFilter->has_product_id = filter.hasProductId()))
37 if (filter.hasProductId()) 36 mojoFilter->product_id = filter.productId();
38 webFilter->productID = filter.productId(); 37 if ((mojoFilter->has_class_code = filter.hasClassCode()))
39 webFilter->hasClassCode = filter.hasClassCode(); 38 mojoFilter->class_code = filter.classCode();
40 if (filter.hasClassCode()) 39 if ((mojoFilter->has_subclass_code = filter.hasSubclassCode()))
41 webFilter->classCode = filter.classCode(); 40 mojoFilter->subclass_code = filter.subclassCode();
42 webFilter->hasSubclassCode = filter.hasSubclassCode(); 41 if ((mojoFilter->has_protocol_code = filter.hasProtocolCode()))
43 if (filter.hasSubclassCode()) 42 mojoFilter->protocol_code = filter.protocolCode();
44 webFilter->subclassCode = filter.subclassCode(); 43 return mojoFilter;
45 webFilter->hasProtocolCode = filter.hasProtocolCode();
46 if (filter.hasProtocolCode())
47 webFilter->protocolCode = filter.protocolCode();
48 } 44 }
49 45
50 void convertDeviceRequestOptions(const USBDeviceRequestOptions& options, WebUSBD eviceRequestOptions* webOptions) 46 bool isActive(ScriptPromiseResolver* resolver)
51 { 47 {
52 DCHECK(options.hasFilters()); 48 ExecutionContext* context = resolver->getExecutionContext();
53 webOptions->filters = WebVector<WebUSBDeviceFilter>(options.filters().size() ); 49 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 } 50 }
58 51
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 52 } // namespace
76 53
77 USB::USB(LocalFrame& frame) 54 USB::USB(LocalFrame& frame)
78 : ContextLifecycleObserver(frame.document()) 55 : ContextLifecycleObserver(frame.document())
79 , m_client(USBController::from(frame).client())
80 { 56 {
81 ThreadState::current()->registerPreFinalizer(this); 57 frame.serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_deviceMana ger));
82 if (m_client) 58 m_deviceManager.set_connection_error_handler([this]() {
83 m_client->addObserver(this); 59 m_deviceManager.reset();
60 for (ScriptPromiseResolver* resolver : m_deviceManagerRequests) {
61 if (isActive(resolver))
62 resolver->reject(DOMException::create(NotFoundError, kNoServiceE rror));
63 }
64 m_deviceManagerRequests.clear();
65 });
66 // Set up two sequential calls to GetDeviceChanges to avoid latency.
67 m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeN otificationPtr>(&USB::onDeviceChanges, this)));
68 m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeN otificationPtr>(&USB::onDeviceChanges, this)));
84 } 69 }
85 70
86 USB::~USB() 71 USB::~USB()
87 { 72 {
88 } 73 DCHECK(!m_deviceManager);
89 74 DCHECK(m_deviceManagerRequests.isEmpty());
90 void USB::dispose() 75 DCHECK(!m_chooserService);
91 { 76 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 } 77 }
98 78
99 ScriptPromise USB::getDevices(ScriptState* scriptState) 79 ScriptPromise USB::getDevices(ScriptState* scriptState)
100 { 80 {
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) ; 81 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
109 ScriptPromise promise = resolver->promise(); 82 ScriptPromise promise = resolver->promise();
110 m_client->getDevices(new CallbackPromiseAdapter<DeviceArray, USBError>(resol ver)); 83 if (!m_deviceManager) {
111 84 resolver->reject(DOMException::create(NotSupportedError));
85 } else {
86 String errorMessage;
87 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
88 resolver->reject(DOMException::create(SecurityError, errorMessage));
89 } else {
90 m_deviceManagerRequests.add(resolver);
91 m_deviceManager->GetDevices(nullptr, createBaseCallback(bind<mojo::W TFArray<usb::DeviceInfoPtr>>(&USB::onGetDevices, this, resolver)));
92 }
93 }
112 return promise; 94 return promise;
113 } 95 }
114 96
115 ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceReques tOptions& options) 97 ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceReques tOptions& options)
116 { 98 {
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) ; 99 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
128 ScriptPromise promise = resolver->promise(); 100 ScriptPromise promise = resolver->promise();
129 101
130 WebUSBDeviceRequestOptions webOptions; 102 if (!m_chooserService) {
131 convertDeviceRequestOptions(options, &webOptions); 103 LocalFrame* frame = getExecutionContext() ? toDocument(getExecutionConte xt())->frame() : nullptr;
132 m_client->requestDevice(webOptions, new CallbackPromiseAdapter<USBDevice, US BError>(resolver)); 104 if (!frame) {
105 resolver->reject(DOMException::create(NotSupportedError));
106 return promise;
107 }
108 frame->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_choos erService));
109 m_chooserService.set_connection_error_handler([this]() {
110 m_chooserService.reset();
111 for (ScriptPromiseResolver* resolver : m_chooserServiceRequests) {
112 if (isActive(resolver))
113 resolver->reject(DOMException::create(NotFoundError, kNoServ iceError));
114 }
115 m_chooserServiceRequests.clear();
116 });
117 }
133 118
119 String errorMessage;
120 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
121 resolver->reject(DOMException::create(SecurityError, errorMessage));
122 } else if (!UserGestureIndicator::consumeUserGesture()) {
123 resolver->reject(DOMException::create(SecurityError, "Must be handling a user gesture to show a permission request."));
124 } else {
125 Vector<usb::DeviceFilterPtr> filters;
126 if (options.hasFilters()) {
127 filters.reserveCapacity(options.filters().size());
128 for (const auto& filter : options.filters())
129 filters.append(convertDeviceFilter(filter));
130 }
131 m_chooserServiceRequests.add(resolver);
132 m_chooserService->GetPermission(std::move(filters), createBaseCallback(b ind<usb::DeviceInfoPtr>(&USB::onGetPermission, this, resolver)));
133 }
134 return promise; 134 return promise;
135 } 135 }
136 136
137 ExecutionContext* USB::getExecutionContext() const 137 ExecutionContext* USB::getExecutionContext() const
138 { 138 {
139 return ContextLifecycleObserver::getExecutionContext(); 139 return ContextLifecycleObserver::getExecutionContext();
140 } 140 }
141 141
142 const AtomicString& USB::interfaceName() const 142 const AtomicString& USB::interfaceName() const
143 { 143 {
144 return EventTargetNames::USB; 144 return EventTargetNames::USB;
145 } 145 }
146 146
147 void USB::contextDestroyed() 147 void USB::contextDestroyed()
148 { 148 {
149 if (m_client) 149 m_deviceManager.reset();
150 m_client->removeObserver(this); 150 m_deviceManagerRequests.clear();
151 m_client = nullptr; 151 m_chooserService.reset();
152 m_chooserServiceRequests.clear();
152 } 153 }
153 154
154 void USB::onDeviceConnected(std::unique_ptr<WebUSBDevice> device) 155 void USB::onGetDevices(ScriptPromiseResolver* resolver, mojo::WTFArray<usb::Devi ceInfoPtr> deviceInfos)
155 { 156 {
156 dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice: :create(adoptPtr(device.release()), getExecutionContext()))); 157 if (!isActive(resolver))
158 return;
159
160 HeapVector<Member<USBDevice>> devices;
161 for (auto& deviceInfo : deviceInfos.PassStorage()) {
162 usb::DevicePtr device;
163 m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
164 devices.append(USBDevice::create(std::move(deviceInfo), std::move(device ), resolver->getExecutionContext()));
165 }
166 resolver->resolve(devices);
167 m_deviceManagerRequests.remove(resolver);
157 } 168 }
158 169
159 void USB::onDeviceDisconnected(std::unique_ptr<WebUSBDevice> device) 170 void USB::onGetPermission(ScriptPromiseResolver* resolver, device::usb::blink::D eviceInfoPtr deviceInfo)
160 { 171 {
161 dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevi ce::create(adoptPtr(device.release()), getExecutionContext()))); 172 if (!isActive(resolver))
173 return;
174
175 if (deviceInfo) {
176 usb::DevicePtr device;
177 m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
178 resolver->resolve(USBDevice::create(std::move(deviceInfo), std::move(dev ice), resolver->getExecutionContext()));
179 } else {
180 resolver->reject(DOMException::create(NotFoundError, "No device selected ."));
181 }
182 }
183
184 void USB::onDeviceChanges(usb::DeviceChangeNotificationPtr notification)
185 {
186 m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeN otificationPtr>(&USB::onDeviceChanges, this)));
187 for (auto& deviceInfo : notification->devices_added.PassStorage()) {
188 usb::DevicePtr device;
189 m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
190 dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDev ice::create(std::move(deviceInfo), std::move(device), getExecutionContext())));
191 }
192 for (auto& deviceInfo : notification->devices_removed.PassStorage())
193 dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USB Device::create(std::move(deviceInfo), nullptr, getExecutionContext())));
162 } 194 }
163 195
164 DEFINE_TRACE(USB) 196 DEFINE_TRACE(USB)
165 { 197 {
166 EventTargetWithInlineData::trace(visitor); 198 EventTargetWithInlineData::trace(visitor);
167 ContextLifecycleObserver::trace(visitor); 199 ContextLifecycleObserver::trace(visitor);
200 visitor->trace(m_deviceManagerRequests);
201 visitor->trace(m_chooserServiceRequests);
168 } 202 }
169 203
170 } // namespace blink 204 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698