Commit 7da3afd2 authored by Keishi Hattori's avatar Keishi Hattori Committed by Commit Bot

Introduce Blink mojo Remote/Receiver wrappers

Adds Blink mojo Remote/Receiver wrappers HeapMojo{Receiver,Remote}
Also uses them in the speech module as an example

Design doc:
https://docs.google.com/document/d/1mYKbNgVzQUbc0zKLjiBcO5Ue_VTh3sIwj8glHU-azQ8/edit

Bug: 1049056
Change-Id: Ia14f455736197f25d1fdbfe78473d3681fd02e37
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2000268
Commit-Queue: Keishi Hattori <keishi@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#742032}
parent 163e3c09
...@@ -46,7 +46,7 @@ SpeechRecognition* SpeechRecognition::Create(ExecutionContext* context) { ...@@ -46,7 +46,7 @@ SpeechRecognition* SpeechRecognition::Create(ExecutionContext* context) {
} }
void SpeechRecognition::start(ExceptionState& exception_state) { void SpeechRecognition::start(ExceptionState& exception_state) {
if (!controller_) if (!controller_ || !GetExecutionContext())
return; return;
if (started_) { if (started_) {
...@@ -57,18 +57,20 @@ void SpeechRecognition::start(ExceptionState& exception_state) { ...@@ -57,18 +57,20 @@ void SpeechRecognition::start(ExceptionState& exception_state) {
final_results_.clear(); final_results_.clear();
// See https://bit.ly/2S0zRAS for task types.
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
GetExecutionContext()->GetTaskRunner(blink::TaskType::kMiscPlatformAPI);
mojo::PendingRemote<mojom::blink::SpeechRecognitionSessionClient> mojo::PendingRemote<mojom::blink::SpeechRecognitionSessionClient>
session_client; session_client;
receiver_.Bind(session_client.InitWithNewPipeAndPassReceiver(), task_runner); // See https://bit.ly/2S0zRAS for task types.
receiver_.Bind(
session_client.InitWithNewPipeAndPassReceiver(),
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
receiver_.set_disconnect_handler(WTF::Bind( receiver_.set_disconnect_handler(WTF::Bind(
&SpeechRecognition::OnConnectionError, WrapWeakPersistent(this))); &SpeechRecognition::OnConnectionError, WrapWeakPersistent(this)));
controller_->Start(session_.BindNewPipeAndPassReceiver(), controller_->Start(
std::move(session_client), *grammars_, lang_, continuous_, session_.BindNewPipeAndPassReceiver(
interim_results_, max_alternatives_); GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)),
std::move(session_client), *grammars_, lang_, continuous_,
interim_results_, max_alternatives_);
started_ = true; started_ = true;
} }
...@@ -186,8 +188,8 @@ ExecutionContext* SpeechRecognition::GetExecutionContext() const { ...@@ -186,8 +188,8 @@ ExecutionContext* SpeechRecognition::GetExecutionContext() const {
void SpeechRecognition::ContextDestroyed() { void SpeechRecognition::ContextDestroyed() {
controller_ = nullptr; controller_ = nullptr;
receiver_.reset();
session_.reset(); session_.reset();
receiver_.reset();
} }
bool SpeechRecognition::HasPendingActivity() const { bool SpeechRecognition::HasPendingActivity() const {
...@@ -221,7 +223,8 @@ SpeechRecognition::SpeechRecognition(LocalFrame* frame, ...@@ -221,7 +223,8 @@ SpeechRecognition::SpeechRecognition(LocalFrame* frame,
controller_(SpeechRecognitionController::From(frame)), controller_(SpeechRecognitionController::From(frame)),
started_(false), started_(false),
stopping_(false), stopping_(false),
receiver_(this) {} receiver_(this, context),
session_(context) {}
SpeechRecognition::~SpeechRecognition() = default; SpeechRecognition::~SpeechRecognition() = default;
...@@ -229,6 +232,8 @@ void SpeechRecognition::Trace(Visitor* visitor) { ...@@ -229,6 +232,8 @@ void SpeechRecognition::Trace(Visitor* visitor) {
visitor->Trace(grammars_); visitor->Trace(grammars_);
visitor->Trace(controller_); visitor->Trace(controller_);
visitor->Trace(final_results_); visitor->Trace(final_results_);
visitor->Trace(receiver_);
visitor->Trace(session_);
EventTargetWithInlineData::Trace(visitor); EventTargetWithInlineData::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor);
PageVisibilityObserver::Trace(visitor); PageVisibilityObserver::Trace(visitor);
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#include "third_party/blink/renderer/modules/speech/speech_grammar_list.h" #include "third_party/blink/renderer/modules/speech/speech_grammar_list.h"
#include "third_party/blink/renderer/modules/speech/speech_recognition_result.h" #include "third_party/blink/renderer/modules/speech/speech_recognition_result.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink { namespace blink {
...@@ -135,8 +137,8 @@ class MODULES_EXPORT SpeechRecognition final ...@@ -135,8 +137,8 @@ class MODULES_EXPORT SpeechRecognition final
bool started_; bool started_;
bool stopping_; bool stopping_;
HeapVector<Member<SpeechRecognitionResult>> final_results_; HeapVector<Member<SpeechRecognitionResult>> final_results_;
mojo::Receiver<mojom::blink::SpeechRecognitionSessionClient> receiver_; HeapMojoReceiver<mojom::blink::SpeechRecognitionSessionClient> receiver_;
mojo::Remote<mojom::blink::SpeechRecognitionSession> session_; HeapMojoRemote<mojom::blink::SpeechRecognitionSession> session_;
}; };
} // namespace blink } // namespace blink
......
...@@ -65,7 +65,9 @@ SpeechSynthesis* SpeechSynthesis::CreateForTesting( ...@@ -65,7 +65,9 @@ SpeechSynthesis* SpeechSynthesis::CreateForTesting(
} }
SpeechSynthesis::SpeechSynthesis(ExecutionContext* context) SpeechSynthesis::SpeechSynthesis(ExecutionContext* context)
: ContextClient(context) { : ContextClient(context),
receiver_(this, context),
mojom_synthesis_(context) {
DCHECK(!GetExecutionContext() || GetExecutionContext()->IsDocument()); DCHECK(!GetExecutionContext() || GetExecutionContext()->IsDocument());
} }
...@@ -194,11 +196,6 @@ void SpeechSynthesis::SentenceBoundaryEventOccurred( ...@@ -194,11 +196,6 @@ void SpeechSynthesis::SentenceBoundaryEventOccurred(
sentence_boundary_string); sentence_boundary_string);
} }
void SpeechSynthesis::Dispose() {
receiver_.reset();
mojom_synthesis_.reset();
}
void SpeechSynthesis::VoicesDidChange() { void SpeechSynthesis::VoicesDidChange() {
if (GetExecutionContext()) if (GetExecutionContext())
DispatchEvent(*Event::Create(event_type_names::kVoiceschanged)); DispatchEvent(*Event::Create(event_type_names::kVoiceschanged));
...@@ -291,6 +288,8 @@ SpeechSynthesisUtterance* SpeechSynthesis::CurrentSpeechUtterance() const { ...@@ -291,6 +288,8 @@ SpeechSynthesisUtterance* SpeechSynthesis::CurrentSpeechUtterance() const {
} }
void SpeechSynthesis::Trace(Visitor* visitor) { void SpeechSynthesis::Trace(Visitor* visitor) {
visitor->Trace(receiver_);
visitor->Trace(mojom_synthesis_);
visitor->Trace(voice_list_); visitor->Trace(voice_list_);
visitor->Trace(utterance_queue_); visitor->Trace(utterance_queue_);
ContextClient::Trace(visitor); ContextClient::Trace(visitor);
...@@ -326,29 +325,36 @@ bool SpeechSynthesis::IsAllowedToStartByAutoplay() const { ...@@ -326,29 +325,36 @@ bool SpeechSynthesis::IsAllowedToStartByAutoplay() const {
void SpeechSynthesis::SetMojomSynthesisForTesting( void SpeechSynthesis::SetMojomSynthesisForTesting(
mojo::PendingRemote<mojom::blink::SpeechSynthesis> mojom_synthesis) { mojo::PendingRemote<mojom::blink::SpeechSynthesis> mojom_synthesis) {
mojom_synthesis_.Bind(std::move(mojom_synthesis)); mojom_synthesis_.Bind(
std::move(mojom_synthesis),
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
receiver_.reset(); receiver_.reset();
mojom_synthesis_->AddVoiceListObserver(receiver_.BindNewPipeAndPassRemote()); mojom_synthesis_->AddVoiceListObserver(receiver_.BindNewPipeAndPassRemote(
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
} }
void SpeechSynthesis::InitializeMojomSynthesis() { void SpeechSynthesis::InitializeMojomSynthesis() {
DCHECK(!mojom_synthesis_); DCHECK(!mojom_synthesis_.is_bound());
auto receiver = mojom_synthesis_.BindNewPipeAndPassReceiver();
// The frame could be detached. In that case, calls on mojom_synthesis_ will // The frame could be detached. In that case, calls on mojom_synthesis_ will
// just get dropped. That's okay and is simpler than having to null-check // just get dropped. That's okay and is simpler than having to null-check
// mojom_synthesis_ before each use. // mojom_synthesis_ before each use.
ExecutionContext* context = GetExecutionContext(); ExecutionContext* context = GetExecutionContext();
if (context) {
context->GetBrowserInterfaceBroker().GetInterface(std::move(receiver));
}
mojom_synthesis_->AddVoiceListObserver(receiver_.BindNewPipeAndPassRemote()); if (!context)
return;
auto receiver = mojom_synthesis_.BindNewPipeAndPassReceiver(
context->GetTaskRunner(TaskType::kMiscPlatformAPI));
context->GetBrowserInterfaceBroker().GetInterface(std::move(receiver));
mojom_synthesis_->AddVoiceListObserver(receiver_.BindNewPipeAndPassRemote(
context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
} }
void SpeechSynthesis::InitializeMojomSynthesisIfNeeded() { void SpeechSynthesis::InitializeMojomSynthesisIfNeeded() {
if (!mojom_synthesis_) if (!mojom_synthesis_.is_bound())
InitializeMojomSynthesis(); InitializeMojomSynthesis();
} }
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/speech/speech_synthesis.mojom-blink-forward.h" #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/event_target_modules.h"
...@@ -35,6 +33,8 @@ ...@@ -35,6 +33,8 @@
#include "third_party/blink/renderer/modules/speech/speech_synthesis_utterance.h" #include "third_party/blink/renderer/modules/speech/speech_synthesis_utterance.h"
#include "third_party/blink/renderer/modules/speech/speech_synthesis_voice.h" #include "third_party/blink/renderer/modules/speech/speech_synthesis_voice.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
namespace blink { namespace blink {
...@@ -43,7 +43,6 @@ class MODULES_EXPORT SpeechSynthesis final ...@@ -43,7 +43,6 @@ class MODULES_EXPORT SpeechSynthesis final
public ContextClient, public ContextClient,
public mojom::blink::SpeechSynthesisVoiceListObserver { public mojom::blink::SpeechSynthesisVoiceListObserver {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(SpeechSynthesis, Dispose);
USING_GARBAGE_COLLECTED_MIXIN(SpeechSynthesis); USING_GARBAGE_COLLECTED_MIXIN(SpeechSynthesis);
public: public:
...@@ -91,15 +90,11 @@ class MODULES_EXPORT SpeechSynthesis final ...@@ -91,15 +90,11 @@ class MODULES_EXPORT SpeechSynthesis final
unsigned char_index, unsigned char_index,
unsigned char_length); unsigned char_length);
mojo::Remote<mojom::blink::SpeechSynthesis>& MojomSynthesis() { mojom::blink::SpeechSynthesis* MojomSynthesis() {
return mojom_synthesis_; return mojom_synthesis_.get();
} }
private: private:
// USING_PRE_FINALIZER interface.
// Called before the object gets garbage collected.
void Dispose();
void VoicesDidChange(); void VoicesDidChange();
void StartSpeakingImmediately(); void StartSpeakingImmediately();
void HandleSpeakingCompleted(SpeechSynthesisUtterance*, bool error_occurred); void HandleSpeakingCompleted(SpeechSynthesisUtterance*, bool error_occurred);
...@@ -127,9 +122,8 @@ class MODULES_EXPORT SpeechSynthesis final ...@@ -127,9 +122,8 @@ class MODULES_EXPORT SpeechSynthesis final
void InitializeMojomSynthesis(); void InitializeMojomSynthesis();
void InitializeMojomSynthesisIfNeeded(); void InitializeMojomSynthesisIfNeeded();
mojo::Receiver<mojom::blink::SpeechSynthesisVoiceListObserver> receiver_{ HeapMojoReceiver<mojom::blink::SpeechSynthesisVoiceListObserver> receiver_;
this}; HeapMojoRemote<mojom::blink::SpeechSynthesis> mojom_synthesis_;
mojo::Remote<mojom::blink::SpeechSynthesis> mojom_synthesis_;
HeapVector<Member<SpeechSynthesisVoice>> voice_list_; HeapVector<Member<SpeechSynthesisVoice>> voice_list_;
HeapDeque<Member<SpeechSynthesisUtterance>> utterance_queue_; HeapDeque<Member<SpeechSynthesisUtterance>> utterance_queue_;
bool is_paused_ = false; bool is_paused_ = false;
......
...@@ -46,6 +46,7 @@ SpeechSynthesisUtterance* SpeechSynthesisUtterance::Create( ...@@ -46,6 +46,7 @@ SpeechSynthesisUtterance* SpeechSynthesisUtterance::Create(
SpeechSynthesisUtterance::SpeechSynthesisUtterance(ExecutionContext* context, SpeechSynthesisUtterance::SpeechSynthesisUtterance(ExecutionContext* context,
const String& text) const String& text)
: ContextClient(context), : ContextClient(context),
receiver_(this, context),
mojom_utterance_(mojom::blink::SpeechSynthesisUtterance::New()) { mojom_utterance_(mojom::blink::SpeechSynthesisUtterance::New()) {
// Set default values. |voice| intentionally left null. // Set default values. |voice| intentionally left null.
mojom_utterance_->text = text; mojom_utterance_->text = text;
...@@ -75,6 +76,7 @@ void SpeechSynthesisUtterance::setVoice(SpeechSynthesisVoice* voice) { ...@@ -75,6 +76,7 @@ void SpeechSynthesisUtterance::setVoice(SpeechSynthesisVoice* voice) {
} }
void SpeechSynthesisUtterance::Trace(Visitor* visitor) { void SpeechSynthesisUtterance::Trace(Visitor* visitor) {
visitor->Trace(receiver_);
visitor->Trace(synthesis_); visitor->Trace(synthesis_);
visitor->Trace(voice_); visitor->Trace(voice_);
ContextClient::Trace(visitor); ContextClient::Trace(visitor);
...@@ -122,6 +124,10 @@ void SpeechSynthesisUtterance::OnEncounteredSpeakingError() { ...@@ -122,6 +124,10 @@ void SpeechSynthesisUtterance::OnEncounteredSpeakingError() {
} }
void SpeechSynthesisUtterance::Start(SpeechSynthesis* synthesis) { void SpeechSynthesisUtterance::Start(SpeechSynthesis* synthesis) {
ExecutionContext* context = GetExecutionContext();
if (!context)
return;
finished_ = false; finished_ = false;
mojom::blink::SpeechSynthesisUtterancePtr mojom_utterance_to_send = mojom::blink::SpeechSynthesisUtterancePtr mojom_utterance_to_send =
...@@ -134,8 +140,10 @@ void SpeechSynthesisUtterance::Start(SpeechSynthesis* synthesis) { ...@@ -134,8 +140,10 @@ void SpeechSynthesisUtterance::Start(SpeechSynthesis* synthesis) {
receiver_.reset(); receiver_.reset();
synthesis_ = synthesis; synthesis_ = synthesis;
synthesis_->MojomSynthesis()->Speak(std::move(mojom_utterance_to_send), synthesis_->MojomSynthesis()->Speak(
receiver_.BindNewPipeAndPassRemote()); std::move(mojom_utterance_to_send),
receiver_.BindNewPipeAndPassRemote(
context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
// Add a disconnect handler so we can cleanup appropriately. // Add a disconnect handler so we can cleanup appropriately.
receiver_.set_disconnect_handler(WTF::Bind( receiver_.set_disconnect_handler(WTF::Bind(
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/speech/speech_synthesis_voice.h" #include "third_party/blink/renderer/modules/speech/speech_synthesis_voice.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink { namespace blink {
...@@ -116,7 +117,7 @@ class SpeechSynthesisUtterance final ...@@ -116,7 +117,7 @@ class SpeechSynthesisUtterance final
// EventTarget // EventTarget
const AtomicString& InterfaceName() const override; const AtomicString& InterfaceName() const override;
mojo::Receiver<mojom::blink::SpeechSynthesisClient> receiver_{this}; HeapMojoReceiver<mojom::blink::SpeechSynthesisClient> receiver_;
mojom::blink::SpeechSynthesisUtterancePtr mojom_utterance_; mojom::blink::SpeechSynthesisUtterancePtr mojom_utterance_;
Member<SpeechSynthesis> synthesis_; Member<SpeechSynthesis> synthesis_;
Member<SpeechSynthesisVoice> voice_; Member<SpeechSynthesisVoice> voice_;
......
...@@ -1225,6 +1225,10 @@ jumbo_component("platform") { ...@@ -1225,6 +1225,10 @@ jumbo_component("platform") {
"mojo/bluetooth_mojom_traits.cc", "mojo/bluetooth_mojom_traits.cc",
"mojo/bluetooth_mojom_traits.h", "mojo/bluetooth_mojom_traits.h",
"mojo/fetch_api_request_headers_mojom_traits.h", "mojo/fetch_api_request_headers_mojom_traits.h",
"mojo/heap_mojo_receiver.h",
"mojo/heap_mojo_receiver.h",
"mojo/heap_mojo_remote.h",
"mojo/heap_mojo_remote.h",
"mojo/kurl_mojom_traits.h", "mojo/kurl_mojom_traits.h",
"mojo/mojo_helper.h", "mojo/mojo_helper.h",
"mojo/security_origin_mojom_traits.h", "mojo/security_origin_mojom_traits.h",
...@@ -1857,6 +1861,8 @@ jumbo_source_set("blink_platform_unittests_sources") { ...@@ -1857,6 +1861,8 @@ jumbo_source_set("blink_platform_unittests_sources") {
"mediastream/webrtc_uma_histograms_test.cc", "mediastream/webrtc_uma_histograms_test.cc",
"mhtml/mhtml_parser_test.cc", "mhtml/mhtml_parser_test.cc",
"mojo/big_string_mojom_traits_test.cc", "mojo/big_string_mojom_traits_test.cc",
"mojo/heap_mojo_receiver_test.cc",
"mojo/heap_mojo_remote_test.cc",
"mojo/kurl_security_origin_test.cc", "mojo/kurl_security_origin_test.cc",
"mojo/string16_mojom_traits_test.cc", "mojo/string16_mojom_traits_test.cc",
"p2p/filtering_network_manager_test.cc", "p2p/filtering_network_manager_test.cc",
......
...@@ -21,6 +21,10 @@ include_rules = [ ...@@ -21,6 +21,10 @@ include_rules = [
"+third_party/blink/renderer/platform/platform_export.h", "+third_party/blink/renderer/platform/platform_export.h",
"+third_party/blink/renderer/platform/weborigin", "+third_party/blink/renderer/platform/weborigin",
"+third_party/blink/renderer/platform/wtf", "+third_party/blink/renderer/platform/wtf",
"+third_party/blink/renderer/platform/context_lifecycle_observer.h",
"+third_party/blink/renderer/platform/context_lifecycle_notifier.h",
"+third_party/blink/renderer/platform/heap_observer_list.h",
"+third_party/blink/renderer/platform/heap",
] ]
specific_include_rules = { specific_include_rules = {
......
// Copyright 2020 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_RECEIVER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_RECEIVER_H_
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
// HeapMojoReceiver is a wrapper for mojo::Receiver to be owned by a
// garbage-collected object. Blink is expected to use HeapMojoReceiver by
// default. HeapMojoReceiver must be associated with context.
// HeapMojoReceiver's constructor takes context as a mandatory parameter.
// HeapMojoReceiver resets the mojo connection when 1) the owner object is
// garbage-collected and 2) the associated ExecutionContext is detached.
template <typename Interface>
class HeapMojoReceiver {
DISALLOW_NEW();
public:
using ImplPointerType = typename mojo::Receiver<Interface>::ImplPointerType;
HeapMojoReceiver(ImplPointerType impl, ContextLifecycleNotifier* context)
: wrapper_(MakeGarbageCollected<Wrapper>(std::move(impl), context)) {}
// Methods to redirect to mojo::Receiver:
ImplPointerType operator->() const { return get(); }
ImplPointerType get() { return wrapper_->receiver().get(); }
bool is_bound() const { return wrapper_->receiver().is_bound(); }
void reset() { wrapper_->receiver().reset(); }
void set_disconnect_handler(base::OnceClosure handler) {
wrapper_->receiver().set_disconnect_handler(std::move(handler));
}
mojo::PendingRemote<Interface> BindNewPipeAndPassRemote(
scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT {
return wrapper_->receiver().BindNewPipeAndPassRemote(
std::move(task_runner));
}
void Bind(mojo::PendingReceiver<Interface> pending_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
wrapper_->receiver().Bind(std::move(pending_receiver),
std::move(task_runner));
}
void Trace(Visitor* visitor) { visitor->Trace(wrapper_); }
private:
// Garbage collected wrapper class to add a prefinalizer.
class Wrapper final : public GarbageCollected<Wrapper>,
public ContextLifecycleObserver {
USING_PRE_FINALIZER(Wrapper, Dispose);
USING_GARBAGE_COLLECTED_MIXIN(Wrapper);
public:
Wrapper(ImplPointerType impl, ContextLifecycleNotifier* notifier)
: receiver_(std::move(impl)) {
SetContextLifecycleNotifier(notifier);
}
void Trace(Visitor* visitor) override {
ContextLifecycleObserver::Trace(visitor);
}
void Dispose() { receiver_.reset(); }
mojo::Receiver<Interface>& receiver() { return receiver_; }
// ContextLifecycleObserver methods
void ContextDestroyed() override { receiver_.reset(); }
private:
mojo::Receiver<Interface> receiver_;
};
Member<Wrapper> wrapper_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_RECEIVER_H_
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
#include "base/test/null_task_runner.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/interfaces/bindings/tests/sample_service.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_list.h"
namespace blink {
class MockContext final : public GarbageCollected<MockContext>,
public ContextLifecycleNotifier {
USING_GARBAGE_COLLECTED_MIXIN(MockContext);
public:
MockContext() = default;
void AddContextLifecycleObserver(
ContextLifecycleObserver* observer) override {
observers_.AddObserver(observer);
}
void RemoveContextLifecycleObserver(
ContextLifecycleObserver* observer) override {
observers_.RemoveObserver(observer);
}
void NotifyContextDestroyed() {
observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
observer->ContextDestroyed();
});
}
void Trace(Visitor* visitor) override {
visitor->Trace(observers_);
ContextLifecycleNotifier::Trace(visitor);
}
private:
HeapObserverList<ContextLifecycleObserver> observers_;
};
class ReceiverOwner : public GarbageCollected<ReceiverOwner>,
public sample::blink::Service {
public:
explicit ReceiverOwner(MockContext* context) : receiver_(this, context) {}
HeapMojoReceiver<sample::blink::Service>& receiver() { return receiver_; }
void Trace(Visitor* visitor) { visitor->Trace(receiver_); }
private:
// sample::blink::Service implementation
void Frobinate(sample::blink::FooPtr foo,
sample::blink::Service::BazOptions options,
mojo::PendingRemote<sample::blink::Port> port,
sample::blink::Service::FrobinateCallback callback) override {}
void GetPort(mojo::PendingReceiver<sample::blink::Port> port) override {}
HeapMojoReceiver<sample::blink::Service> receiver_;
};
class HeapMojoReceiverTest : public TestSupportingGC {
public:
base::RunLoop& run_loop() { return run_loop_; }
bool& disconnected() { return disconnected_; }
void ClearOwner() { owner_ = nullptr; }
protected:
void SetUp() override {
CHECK(!disconnected_);
context_ = MakeGarbageCollected<MockContext>();
owner_ = MakeGarbageCollected<ReceiverOwner>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
remote_ = mojo::Remote<sample::blink::Service>(
owner_->receiver().BindNewPipeAndPassRemote(null_task_runner));
remote_.set_disconnect_handler(WTF::Bind(
[](HeapMojoReceiverTest* receiver_test) {
receiver_test->run_loop().Quit();
receiver_test->disconnected() = true;
},
WTF::Unretained(this)));
}
void TearDown() override { CHECK(disconnected_); }
Persistent<MockContext> context_;
Persistent<ReceiverOwner> owner_;
base::RunLoop run_loop_;
mojo::Remote<sample::blink::Service> remote_;
bool disconnected_ = false;
};
// Make HeapMojoReceiver garbage collected and check that the connection is
// disconnected right after the marking phase.
TEST_F(HeapMojoReceiverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
PreciselyCollectGarbage(BlinkGC::kConcurrentAndLazySweeping);
run_loop().Run();
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
// Destroy the context and check that the connection is disconnected.
TEST_F(HeapMojoReceiverTest, ResetsOnContextDestroyed) {
EXPECT_FALSE(disconnected());
context_->NotifyContextDestroyed();
run_loop().Run();
EXPECT_TRUE(disconnected());
}
} // namespace blink
// Copyright 2020 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_REMOTE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_REMOTE_H_
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
// HeapMojoRemote is a wrapper for mojo::Receiver to be owned by a
// garbage-collected object. Blink is expected to use HeapMojoRemote by
// default. HeapMojoRemote must be associated with context.
// HeapMojoRemote's constructor takes context as a mandatory parameter.
// HeapMojoRemote resets the mojo connection when 1) the owner object is
// garbage-collected and 2) the associated ExecutionContext is detached.
template <typename Interface>
class HeapMojoRemote {
DISALLOW_NEW();
public:
using ImplPointerType = typename mojo::Receiver<Interface>::ImplPointerType;
HeapMojoRemote(ContextLifecycleNotifier* notifier)
: wrapper_(MakeGarbageCollected<Wrapper>(notifier)) {}
// Methods to redirect to mojo::Receiver:
ImplPointerType operator->() const { return get(); }
ImplPointerType get() const { return wrapper_->remote().get(); }
bool is_bound() const { return wrapper_->remote().is_bound(); }
bool is_connected() const { return wrapper_->remote().is_connected(); }
void reset() { wrapper_->remote().reset(); }
void set_disconnect_handler(base::OnceClosure handler) {
wrapper_->remote().set_disconnect_handler(std::move(handler));
}
mojo::PendingReceiver<Interface> BindNewPipeAndPassReceiver(
scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT {
return wrapper_->remote().BindNewPipeAndPassReceiver(
std::move(task_runner));
}
void Bind(mojo::PendingRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
wrapper_->remote().Bind(std::move(pending_remote), std::move(task_runner));
}
void Trace(Visitor* visitor) { visitor->Trace(wrapper_); }
private:
// Garbage collected wrapper class to add a prefinalizer.
class Wrapper final : public GarbageCollected<Wrapper>,
public ContextLifecycleObserver {
USING_PRE_FINALIZER(Wrapper, Dispose);
USING_GARBAGE_COLLECTED_MIXIN(Wrapper);
public:
Wrapper(ContextLifecycleNotifier* notifier) {
SetContextLifecycleNotifier(notifier);
}
void Trace(Visitor* visitor) override {
ContextLifecycleObserver::Trace(visitor);
}
void Dispose() { remote_.reset(); }
mojo::Remote<Interface>& remote() { return remote_; }
// ContextLifecycleObserver methods
void ContextDestroyed() override { remote_.reset(); }
private:
mojo::Remote<Interface> remote_;
};
Member<Wrapper> wrapper_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_REMOTE_H_
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
#include "base/test/null_task_runner.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/interfaces/bindings/tests/sample_service.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_list.h"
namespace blink {
class MockContext final : public GarbageCollected<MockContext>,
public ContextLifecycleNotifier {
USING_GARBAGE_COLLECTED_MIXIN(MockContext);
public:
MockContext() = default;
void AddContextLifecycleObserver(
ContextLifecycleObserver* observer) override {
observers_.AddObserver(observer);
}
void RemoveContextLifecycleObserver(
ContextLifecycleObserver* observer) override {
observers_.RemoveObserver(observer);
}
void NotifyContextDestroyed() {
observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
observer->ContextDestroyed();
});
}
void Trace(Visitor* visitor) override {
visitor->Trace(observers_);
ContextLifecycleNotifier::Trace(visitor);
}
private:
HeapObserverList<ContextLifecycleObserver> observers_;
};
class ServiceImpl : public sample::blink::Service {
public:
explicit ServiceImpl() = default;
mojo::Receiver<sample::blink::Service>& receiver() { return receiver_; }
private:
// sample::blink::Service implementation
void Frobinate(sample::blink::FooPtr foo,
sample::blink::Service::BazOptions options,
mojo::PendingRemote<sample::blink::Port> port,
sample::blink::Service::FrobinateCallback callback) override {}
void GetPort(mojo::PendingReceiver<sample::blink::Port> port) override {}
mojo::Receiver<sample::blink::Service> receiver_{this};
};
class RemoteOwner : public GarbageCollected<RemoteOwner> {
public:
explicit RemoteOwner(MockContext* context) : remote_(context) {}
HeapMojoRemote<sample::blink::Service>& remote() { return remote_; }
void Trace(Visitor* visitor) { visitor->Trace(remote_); }
HeapMojoRemote<sample::blink::Service> remote_;
};
class HeapMojoRemoteTest : public TestSupportingGC {
public:
base::RunLoop& run_loop() { return run_loop_; }
bool& disconnected() { return disconnected_; }
void ClearOwner() { owner_ = nullptr; }
protected:
void SetUp() override {
CHECK(!disconnected_);
context_ = MakeGarbageCollected<MockContext>();
owner_ = MakeGarbageCollected<RemoteOwner>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
impl_.receiver().Bind(
owner_->remote().BindNewPipeAndPassReceiver(null_task_runner));
impl_.receiver().set_disconnect_handler(WTF::Bind(
[](HeapMojoRemoteTest* remote_test) {
remote_test->run_loop().Quit();
remote_test->disconnected() = true;
},
WTF::Unretained(this)));
}
void TearDown() override {
// CHECK(disconnected_);
}
ServiceImpl impl_;
Persistent<MockContext> context_;
Persistent<RemoteOwner> owner_;
base::RunLoop run_loop_;
bool disconnected_ = false;
};
// Make HeapMojoRemote garbage collected and check that the connection is
// disconnected right after the marking phase.
TEST_F(HeapMojoRemoteTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
PreciselyCollectGarbage(BlinkGC::kConcurrentAndLazySweeping);
run_loop().Run();
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
// Destroy the context and check that the connection is disconnected.
TEST_F(HeapMojoRemoteTest, ResetsOnContextDestroyed) {
EXPECT_FALSE(disconnected());
context_->NotifyContextDestroyed();
run_loop().Run();
EXPECT_TRUE(disconnected());
}
} // namespace blink
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