Commit fe5c2f3d authored by Reilly Grant's avatar Reilly Grant Committed by Commit Bot

Dispatch interfacerequest event in a new microtask

This change modifies the MojoInterfaceInterceptor so that the
'interfacerequest' event, fired when a request for the intercepted
interface is made, is dispatched in a new microtask instead of
synchronously.

This has the benefit of not reentering JavaScript to execute event
handlers synchronously which is both different from the usual case for
binding interfaces that are provided by other processes and avoids the
possibilty of attempting to dispatch this event to JavaScript from a
scope where script is forbidden.

Change-Id: I08b8c25a04da047381a3786af08b62979ca7b837
Reviewed-on: https://chromium-review.googlesource.com/594716Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarYuzhu Shen <yzshen@chromium.org>
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491552}
parent 335b6a57
...@@ -77,25 +77,41 @@ promise_test(() => { ...@@ -77,25 +77,41 @@ promise_test(() => {
return Promise.reject(); return Promise.reject();
}, "interface interceptors are mutually exclusive"); }, "interface interceptors are mutually exclusive");
test(() => { test(async t => {
const kTestInterfaceName = "foo::mojom::Bar"; const kTestInterfaceName = "foo::mojom::Bar";
let interceptedHandle = null;
// First check that the interceptor can be started and intercepts requests.
let interceptor = new MojoInterfaceInterceptor(kTestInterfaceName); let interceptor = new MojoInterfaceInterceptor(kTestInterfaceName);
interceptor.oninterfacerequest = e => { interceptedHandle = e.handle; }; let promise = new Promise(resolve => {
interceptor.oninterfacerequest = e => {
resolve(e.handle);
};
});
interceptor.start(); interceptor.start();
let {handle0, handle1} = Mojo.createMessagePipe(); let pipe = Mojo.createMessagePipe();
Mojo.bindInterface(kTestInterfaceName, handle0); Mojo.bindInterface(kTestInterfaceName, pipe.handle0);
interceptor.stop(); let interceptedHandle = await promise;
assert_true(interceptedHandle instanceof MojoHandle); assert_true(interceptedHandle instanceof MojoHandle);
interceptedHandle.close(); interceptedHandle.close();
interceptedHandle = null; pipe.handle1.close();
Mojo.bindInterface(kTestInterfaceName, handle1); // Stop the interceptor and make another request.
assert_equals(interceptedHandle, null); interceptor.stop();
handle1.close();
pipe = Mojo.createMessagePipe();
interceptor.oninterfacerequest = t.step_func(() => {
assert_unreached("unexpected 'interfacerequest' event after stop");
});
promise = new Promise(resolve => {
let watcher = pipe.handle1.watch({peerClosed: true}, () => {
watcher.cancel(); // Necessary to avoid a DCHECK when handle1 is closed.
resolve();
});
});
Mojo.bindInterface(kTestInterfaceName, pipe.handle0);
await promise;
pipe.handle1.close();
interceptor = new MojoInterfaceInterceptor(kTestInterfaceName); interceptor = new MojoInterfaceInterceptor(kTestInterfaceName);
interceptor.oninterfacerequest = e => {}; interceptor.oninterfacerequest = e => {};
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/ExecutionContext.h" #include "core/dom/ExecutionContext.h"
#include "core/dom/TaskRunnerHelper.h"
#include "core/frame/LocalDOMWindow.h" #include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h" #include "core/frame/LocalFrame.h"
#include "core/frame/LocalFrameClient.h" #include "core/frame/LocalFrameClient.h"
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include "core/mojo/test/MojoInterfaceRequestEvent.h" #include "core/mojo/test/MojoInterfaceRequestEvent.h"
#include "core/workers/WorkerGlobalScope.h" #include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerThread.h" #include "core/workers/WorkerThread.h"
#include "platform/WebTaskRunner.h"
#include "platform/bindings/ScriptState.h" #include "platform/bindings/ScriptState.h"
#include "platform/wtf/text/StringUTF8Adaptor.h" #include "platform/wtf/text/StringUTF8Adaptor.h"
#include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/public/cpp/interface_provider.h"
...@@ -118,6 +120,20 @@ MojoInterfaceInterceptor::GetInterfaceProvider() const { ...@@ -118,6 +120,20 @@ MojoInterfaceInterceptor::GetInterfaceProvider() const {
void MojoInterfaceInterceptor::OnInterfaceRequest( void MojoInterfaceInterceptor::OnInterfaceRequest(
mojo::ScopedMessagePipeHandle handle) { mojo::ScopedMessagePipeHandle handle) {
// Execution of JavaScript may be forbidden in this context as this method is
// called synchronously by the InterfaceProvider. Dispatching of the
// 'interfacerequest' event is therefore scheduled to take place in the next
// microtask. This also more closely mirrors the behavior when an interface
// request is being satisfied by another process.
TaskRunnerHelper::Get(TaskType::kMicrotask, GetExecutionContext())
->PostTask(
BLINK_FROM_HERE,
WTF::Bind(&MojoInterfaceInterceptor::DispatchInterfaceRequestEvent,
WrapPersistent(this), WTF::Passed(std::move(handle))));
}
void MojoInterfaceInterceptor::DispatchInterfaceRequestEvent(
mojo::ScopedMessagePipeHandle handle) {
DispatchEvent(MojoInterfaceRequestEvent::Create( DispatchEvent(MojoInterfaceRequestEvent::Create(
MojoHandle::Create(mojo::ScopedHandle::From(std::move(handle))))); MojoHandle::Create(mojo::ScopedHandle::From(std::move(handle)))));
} }
......
...@@ -65,6 +65,7 @@ class MojoInterfaceInterceptor final ...@@ -65,6 +65,7 @@ class MojoInterfaceInterceptor final
service_manager::InterfaceProvider* GetInterfaceProvider() const; service_manager::InterfaceProvider* GetInterfaceProvider() const;
void OnInterfaceRequest(mojo::ScopedMessagePipeHandle); void OnInterfaceRequest(mojo::ScopedMessagePipeHandle);
void DispatchInterfaceRequestEvent(mojo::ScopedMessagePipeHandle);
const String interface_name_; const String interface_name_;
bool started_ = false; bool started_ = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment