Commit 3915a08a authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[CRD iOS] Fix thread issue of RendererProxy and QueuedTaskPoster

RendererProxy is used mainly on the UI thread, but it is deleted on the
display thread because GlDisplayRenderer binds its WeakPtrFactory to
the display thread when initializing it. This forces QueuedTaskPoster
to be deleted on the wrong thread, which may be a source of crash. You
can see more details in the bug.

This CL resolves this by making GlDisplayRenderer::Core initialize
RendererProxy on the UI thread.

Bug: 872944
Change-Id: I37dbd20aad80dd05e4eb0ad410c339fdfa5053c5
Reviewed-on: https://chromium-review.googlesource.com/1170133
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: default avatarJamie Walch <jamiewalch@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582674}
parent 0c72ff00
...@@ -15,12 +15,12 @@ namespace remoting { ...@@ -15,12 +15,12 @@ namespace remoting {
RendererProxy::RendererProxy( RendererProxy::RendererProxy(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: task_runner_(task_runner), : task_runner_(task_runner),
ui_task_poster_(new remoting::QueuedTaskPoster(task_runner_)), ui_task_poster_(new remoting::QueuedTaskPoster(task_runner_)) {}
weak_factory_(this) {}
RendererProxy::~RendererProxy() = default; RendererProxy::~RendererProxy() = default;
void RendererProxy::Initialize(base::WeakPtr<GlRenderer> renderer) { void RendererProxy::Initialize(base::WeakPtr<GlRenderer> renderer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
renderer_ = renderer; renderer_ = renderer;
} }
...@@ -49,12 +49,9 @@ void RendererProxy::StartInputFeedback(float x, float y, float diameter) { ...@@ -49,12 +49,9 @@ void RendererProxy::StartInputFeedback(float x, float y, float diameter) {
false); false);
} }
base::WeakPtr<RendererProxy> RendererProxy::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void RendererProxy::RunTaskOnProperThread(const base::Closure& task, void RendererProxy::RunTaskOnProperThread(const base::Closure& task,
bool needs_synchronization) { bool needs_synchronization) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (task_runner_->BelongsToCurrentThread()) { if (task_runner_->BelongsToCurrentThread()) {
task.Run(); task.Run();
return; return;
......
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#ifndef REMOTING_CLIENT_UI_RENDERER_PROXY_H_ #ifndef REMOTING_CLIENT_UI_RENDERER_PROXY_H_
#define REMOTING_CLIENT_UI_RENDERER_PROXY_H_ #define REMOTING_CLIENT_UI_RENDERER_PROXY_H_
#include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
namespace remoting { namespace remoting {
...@@ -15,7 +17,8 @@ class GlRenderer; ...@@ -15,7 +17,8 @@ class GlRenderer;
class QueuedTaskPoster; class QueuedTaskPoster;
class ViewMatrix; class ViewMatrix;
// A class to proxy calls to GlRenderer from one thread to another. // A class to proxy calls to GlRenderer from one thread to another. Must be
// created and used on the same thread.
// TODO(yuweih): This should be removed once we have moved Drawables out of // TODO(yuweih): This should be removed once we have moved Drawables out of
// GlRenderer. // GlRenderer.
class RendererProxy { class RendererProxy {
...@@ -32,8 +35,6 @@ class RendererProxy { ...@@ -32,8 +35,6 @@ class RendererProxy {
void SetCursorVisibility(bool visible); void SetCursorVisibility(bool visible);
void StartInputFeedback(float x, float y, float diameter); void StartInputFeedback(float x, float y, float diameter);
base::WeakPtr<RendererProxy> GetWeakPtr();
private: private:
// Runs the |task| on the thread of |task_runner_|. All tasks run with // Runs the |task| on the thread of |task_runner_|. All tasks run with
// |needs_synchronization| set to true inside the same tick will be run on // |needs_synchronization| set to true inside the same tick will be run on
...@@ -45,11 +46,9 @@ class RendererProxy { ...@@ -45,11 +46,9 @@ class RendererProxy {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
std::unique_ptr<remoting::QueuedTaskPoster> ui_task_poster_; std::unique_ptr<remoting::QueuedTaskPoster> ui_task_poster_;
base::WeakPtrFactory<RendererProxy> weak_factory_; THREAD_CHECKER(thread_checker_);
// RenderStubProxy is neither copyable nor movable. DISALLOW_COPY_AND_ASSIGN(RendererProxy);
RendererProxy(const RendererProxy&) = delete;
RendererProxy& operator=(const RendererProxy&) = delete;
}; };
} // namespace remoting } // namespace remoting
......
...@@ -16,7 +16,11 @@ QueuedTaskPoster::QueuedTaskPoster( ...@@ -16,7 +16,11 @@ QueuedTaskPoster::QueuedTaskPoster(
: target_task_runner_(target_task_runner), : target_task_runner_(target_task_runner),
weak_factory_(this) {} weak_factory_(this) {}
QueuedTaskPoster::~QueuedTaskPoster() = default; QueuedTaskPoster::~QueuedTaskPoster() {
if (source_task_runner_) {
DCHECK(source_task_runner_->BelongsToCurrentThread());
}
}
void QueuedTaskPoster::AddTask(const base::Closure& closure) { void QueuedTaskPoster::AddTask(const base::Closure& closure) {
if (!source_task_runner_) { if (!source_task_runner_) {
......
...@@ -54,9 +54,10 @@ class CursorShapeStub; ...@@ -54,9 +54,10 @@ class CursorShapeStub;
- (void)setSurfaceSize:(const CGRect&)frame; - (void)setSurfaceSize:(const CGRect&)frame;
// Must be called immediately after the object is constructed. // Must be called immediately after the object is constructed.
- (std::unique_ptr<remoting::RendererProxy>)CreateRendererProxy; - (std::unique_ptr<remoting::protocol::VideoRenderer>)createVideoRenderer;
- (std::unique_ptr<remoting::protocol::VideoRenderer>)CreateVideoRenderer; - (std::unique_ptr<remoting::protocol::CursorShapeStub>)createCursorShapeStub;
- (std::unique_ptr<remoting::protocol::CursorShapeStub>)CreateCursorShapeStub;
@property(readonly) remoting::RendererProxy* rendererProxy;
// This is write-only but @property doesn't support write-only modifier. // This is write-only but @property doesn't support write-only modifier.
@property id<GlDisplayHandlerDelegate> delegate; @property id<GlDisplayHandlerDelegate> delegate;
......
...@@ -44,8 +44,6 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate { ...@@ -44,8 +44,6 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate {
void SetHandlerDelegate(id<GlDisplayHandlerDelegate> delegate); void SetHandlerDelegate(id<GlDisplayHandlerDelegate> delegate);
std::unique_ptr<RendererProxy> GrabRendererProxy();
// CursorShapeStub interface. // CursorShapeStub interface.
void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override; void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override;
...@@ -62,16 +60,15 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate { ...@@ -62,16 +60,15 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate {
std::unique_ptr<protocol::FrameConsumer> GrabFrameConsumer(); std::unique_ptr<protocol::FrameConsumer> GrabFrameConsumer();
// The renderer proxy should be used on the UI thread.
RendererProxy* renderer_proxy() { return renderer_proxy_.get(); }
// Returns a weak pointer to be used on the display thread. // Returns a weak pointer to be used on the display thread.
base::WeakPtr<Core> GetWeakPtr(); base::WeakPtr<Core> GetWeakPtr();
private: private:
remoting::ChromotingClientRuntime* runtime_; remoting::ChromotingClientRuntime* runtime_;
// Will be std::move'd when GrabRendererProxy() is called.
std::unique_ptr<RendererProxy> owned_renderer_proxy_;
base::WeakPtr<RendererProxy> renderer_proxy_;
// Will be std::move'd when GrabFrameConsumer() is called. // Will be std::move'd when GrabFrameConsumer() is called.
std::unique_ptr<DualBufferFrameConsumer> owned_frame_consumer_; std::unique_ptr<DualBufferFrameConsumer> owned_frame_consumer_;
base::WeakPtr<DualBufferFrameConsumer> frame_consumer_; base::WeakPtr<DualBufferFrameConsumer> frame_consumer_;
...@@ -80,6 +77,9 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate { ...@@ -80,6 +77,9 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate {
std::unique_ptr<GlRenderer> renderer_; std::unique_ptr<GlRenderer> renderer_;
__weak id<GlDisplayHandlerDelegate> handler_delegate_; __weak id<GlDisplayHandlerDelegate> handler_delegate_;
// This should be used and deleted on the UI thread.
std::unique_ptr<RendererProxy> renderer_proxy_;
// Valid only when the surface is created. // Valid only when the surface is created.
__weak EAGLView* view_; __weak EAGLView* view_;
...@@ -92,7 +92,7 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate { ...@@ -92,7 +92,7 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate {
Core::Core() : weak_factory_(this) { Core::Core() : weak_factory_(this) {
runtime_ = ChromotingClientRuntime::GetInstance(); runtime_ = ChromotingClientRuntime::GetInstance();
DCHECK(!runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread());
weak_ptr_ = weak_factory_.GetWeakPtr(); weak_ptr_ = weak_factory_.GetWeakPtr();
...@@ -103,9 +103,8 @@ Core::Core() : weak_factory_(this) { ...@@ -103,9 +103,8 @@ Core::Core() : weak_factory_(this) {
protocol::FrameConsumer::PixelFormat::FORMAT_RGBA)); protocol::FrameConsumer::PixelFormat::FORMAT_RGBA));
frame_consumer_ = owned_frame_consumer_->GetWeakPtr(); frame_consumer_ = owned_frame_consumer_->GetWeakPtr();
owned_renderer_proxy_.reset( renderer_proxy_ =
new RendererProxy(runtime_->display_task_runner())); std::make_unique<RendererProxy>(runtime_->display_task_runner());
renderer_proxy_ = owned_renderer_proxy_->GetWeakPtr();
runtime_->display_task_runner()->PostTask( runtime_->display_task_runner()->PostTask(
FROM_HERE, base::Bind(&Core::Initialize, GetWeakPtr())); FROM_HERE, base::Bind(&Core::Initialize, GetWeakPtr()));
...@@ -113,6 +112,7 @@ Core::Core() : weak_factory_(this) { ...@@ -113,6 +112,7 @@ Core::Core() : weak_factory_(this) {
Core::~Core() { Core::~Core() {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
runtime_->ui_task_runner()->DeleteSoon(FROM_HERE, renderer_proxy_.release());
} }
void Core::Initialize() { void Core::Initialize() {
...@@ -134,9 +134,14 @@ void Core::Initialize() { ...@@ -134,9 +134,14 @@ void Core::Initialize() {
renderer_ = remoting::GlRenderer::CreateGlRendererWithDesktop(); renderer_ = remoting::GlRenderer::CreateGlRendererWithDesktop();
renderer_proxy_->Initialize(renderer_->GetWeakPtr());
renderer_->SetDelegate(weak_ptr_); renderer_->SetDelegate(weak_ptr_);
// Safe to use base::Unretained because |renderer_proxy_| is destroyed on UI
// after Core is destroyed.
runtime_->ui_task_runner()->PostTask(
FROM_HERE, base::BindOnce(&RendererProxy::Initialize,
base::Unretained(renderer_proxy_.get()),
renderer_->GetWeakPtr()));
} }
void Core::SetHandlerDelegate(id<GlDisplayHandlerDelegate> delegate) { void Core::SetHandlerDelegate(id<GlDisplayHandlerDelegate> delegate) {
...@@ -144,11 +149,6 @@ void Core::SetHandlerDelegate(id<GlDisplayHandlerDelegate> delegate) { ...@@ -144,11 +149,6 @@ void Core::SetHandlerDelegate(id<GlDisplayHandlerDelegate> delegate) {
handler_delegate_ = delegate; handler_delegate_ = delegate;
} }
std::unique_ptr<RendererProxy> Core::GrabRendererProxy() {
DCHECK(owned_renderer_proxy_);
return std::move(owned_renderer_proxy_);
}
void Core::SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) { void Core::SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_->OnCursorShapeChanged(cursor_shape); renderer_->OnCursorShapeChanged(cursor_shape);
...@@ -265,16 +265,12 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() { ...@@ -265,16 +265,12 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() {
#pragma mark - Public #pragma mark - Public
- (std::unique_ptr<remoting::RendererProxy>)CreateRendererProxy { - (std::unique_ptr<remoting::protocol::VideoRenderer>)createVideoRenderer {
return _core->GrabRendererProxy();
}
- (std::unique_ptr<remoting::protocol::VideoRenderer>)CreateVideoRenderer {
return std::make_unique<remoting::SoftwareVideoRenderer>( return std::make_unique<remoting::SoftwareVideoRenderer>(
_core->GrabFrameConsumer()); _core->GrabFrameConsumer());
} }
- (std::unique_ptr<remoting::protocol::CursorShapeStub>)CreateCursorShapeStub { - (std::unique_ptr<remoting::protocol::CursorShapeStub>)createCursorShapeStub {
return std::make_unique<remoting::CursorShapeStubProxy>( return std::make_unique<remoting::CursorShapeStubProxy>(
_core->GetWeakPtr(), _runtime->display_task_runner()); _core->GetWeakPtr(), _runtime->display_task_runner());
} }
...@@ -302,6 +298,10 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() { ...@@ -302,6 +298,10 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() {
#pragma mark - Properties #pragma mark - Properties
- (remoting::RendererProxy*)rendererProxy {
return _core->renderer_proxy();
}
- (void)setDelegate:(id<GlDisplayHandlerDelegate>)delegate { - (void)setDelegate:(id<GlDisplayHandlerDelegate>)delegate {
_runtime->display_task_runner()->PostTask( _runtime->display_task_runner()->PostTask(
FROM_HERE, FROM_HERE,
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "remoting/client/chromoting_client_runtime.h" #include "remoting/client/chromoting_client_runtime.h"
#include "remoting/client/chromoting_session.h" #include "remoting/client/chromoting_session.h"
#include "remoting/client/connect_to_host_info.h" #include "remoting/client/connect_to_host_info.h"
#include "remoting/client/display/renderer_proxy.h"
#include "remoting/client/gesture_interpreter.h" #include "remoting/client/gesture_interpreter.h"
#include "remoting/client/input/keyboard_interpreter.h" #include "remoting/client/input/keyboard_interpreter.h"
#import "remoting/ios/facade/remoting_authentication.h" #import "remoting/ios/facade/remoting_authentication.h"
...@@ -67,7 +66,6 @@ static void ResolveFeedbackDataCallback( ...@@ -67,7 +66,6 @@ static void ResolveFeedbackDataCallback(
remoting::protocol::SecretFetchedCallback _secretFetchedCallback; remoting::protocol::SecretFetchedCallback _secretFetchedCallback;
remoting::GestureInterpreter _gestureInterpreter; remoting::GestureInterpreter _gestureInterpreter;
remoting::KeyboardInterpreter _keyboardInterpreter; remoting::KeyboardInterpreter _keyboardInterpreter;
std::unique_ptr<remoting::RendererProxy> _renderer;
// _session is valid only when the session is connected. // _session is valid only when the session is connected.
std::unique_ptr<remoting::ChromotingSession> _session; std::unique_ptr<remoting::ChromotingSession> _session;
...@@ -142,10 +140,9 @@ static void ResolveFeedbackDataCallback( ...@@ -142,10 +140,9 @@ static void ResolveFeedbackDataCallback(
_displayHandler.delegate = self; _displayHandler.delegate = self;
_session.reset(new remoting::ChromotingSession( _session.reset(new remoting::ChromotingSession(
_sessonDelegate->GetWeakPtr(), [_displayHandler CreateCursorShapeStub], _sessonDelegate->GetWeakPtr(), [_displayHandler createCursorShapeStub],
[_displayHandler CreateVideoRenderer], std::move(audioStream), info)); [_displayHandler createVideoRenderer], std::move(audioStream), info));
_renderer = [_displayHandler CreateRendererProxy]; _gestureInterpreter.SetContext(_displayHandler.rendererProxy, _session.get());
_gestureInterpreter.SetContext(_renderer.get(), _session.get());
_keyboardInterpreter.SetContext(_session.get()); _keyboardInterpreter.SetContext(_session.get());
_session->Connect(); _session->Connect();
...@@ -156,14 +153,6 @@ static void ResolveFeedbackDataCallback( ...@@ -156,14 +153,6 @@ static void ResolveFeedbackDataCallback(
_displayHandler = nil; _displayHandler = nil;
// This needs to be deleted on the display thread since GlDisplayHandler binds
// its WeakPtrFactory to the display thread.
// TODO(yuweih): Ideally this constraint can be removed once we allow
// GlRenderer to be created on the UI thread before being used.
if (_renderer) {
_runtime->display_task_runner()->DeleteSoon(FROM_HERE, _renderer.release());
}
_gestureInterpreter.SetContext(nullptr, nullptr); _gestureInterpreter.SetContext(nullptr, nullptr);
_keyboardInterpreter.SetContext(nullptr); _keyboardInterpreter.SetContext(nullptr);
} }
......
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