Commit 9e9ae0c6 authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[CRD iOS] Fix crash for executing OpenGL commands when app goes to the background

iOS doesn't allow app executing OpenGL commands after it goes to the
background. Disabling the video stream on the host isn't good enough as
the coming video frame will still arrive.

This CL fixes the crash by destroying the OpenGL context when the app
becomes inactive, and recreates the context when the app becomes active
again.

Note that even after we fix the crash, the session will still be
disconnected, since the app will eventually enter the Suspended state
and stop processing network events. See link about an iOS app's
lifecycle:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW3

Bug: 829449
Change-Id: I507b8e2a856b3e019db99faff188bd5f312c5a51
Reviewed-on: https://chromium-review.googlesource.com/1013244
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: default avatarJamie Walch <jamiewalch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551097}
parent 97fcb105
...@@ -53,8 +53,8 @@ void GlRenderer::OnPixelTransformationChanged( ...@@ -53,8 +53,8 @@ void GlRenderer::OnPixelTransformationChanged(
const std::array<float, 9>& matrix) { const std::array<float, 9>& matrix) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (!canvas_) { if (!canvas_) {
LOG(WARNING) << "Trying to set transformation matrix when the canvas is " VLOG(1) << "Trying to set transformation matrix when the canvas is not "
"not ready."; << "ready.";
return; return;
} }
canvas_->SetTransformationMatrix(matrix); canvas_->SetTransformationMatrix(matrix);
......
...@@ -46,7 +46,6 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext"; ...@@ -46,7 +46,6 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
ClientGestures* _clientGestures; ClientGestures* _clientGestures;
ClientKeyboard* _clientKeyboard; ClientKeyboard* _clientKeyboard;
CGSize _keyboardSize; CGSize _keyboardSize;
BOOL _surfaceCreated;
HostSettings* _settings; HostSettings* _settings;
// Used to blur the content when the app enters background. // Used to blur the content when the app enters background.
...@@ -80,7 +79,6 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext"; ...@@ -80,7 +79,6 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
if (self) { if (self) {
_client = client; _client = client;
_keyboardSize = CGSizeZero; _keyboardSize = CGSizeZero;
_surfaceCreated = NO;
_blocksKeyboard = NO; _blocksKeyboard = NO;
_settings = _settings =
[[RemotingPreferences instance] settingsForHost:client.hostInfo.hostId]; [[RemotingPreferences instance] settingsForHost:client.hostInfo.hostId];
...@@ -197,10 +195,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext"; ...@@ -197,10 +195,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
- (void)viewDidAppear:(BOOL)animated { - (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated]; [super viewDidAppear:animated];
if (!_surfaceCreated) { [_client.displayHandler createRendererContext:_hostView];
[_client.displayHandler onSurfaceCreated:_hostView];
_surfaceCreated = YES;
}
// |_clientKeyboard| should always be the first responder even when the soft // |_clientKeyboard| should always be the first responder even when the soft
// keyboard is not visible, so that input from physical keyboard can still be // keyboard is not visible, so that input from physical keyboard can still be
...@@ -272,7 +267,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext"; ...@@ -272,7 +267,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
[super viewDidLayoutSubviews]; [super viewDidLayoutSubviews];
// Pass the actual size of the view to the renderer. // Pass the actual size of the view to the renderer.
[_client.displayHandler onSurfaceChanged:_hostView.bounds]; [_client.displayHandler setSurfaceSize:_hostView.bounds];
// Start the animation on the host's visible area. // Start the animation on the host's visible area.
_surfaceSizeAnimationLink.paused = NO; _surfaceSizeAnimationLink.paused = NO;
...@@ -646,6 +641,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext"; ...@@ -646,6 +641,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
LOG(DFATAL) << "Blur view does not exist."; LOG(DFATAL) << "Blur view does not exist.";
return; return;
} }
[_client.displayHandler createRendererContext:_hostView];
[_client setVideoChannelEnabled:YES]; [_client setVideoChannelEnabled:YES];
[_blurView removeFromSuperview]; [_blurView removeFromSuperview];
_blurView = nil; _blurView = nil;
...@@ -668,6 +664,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext"; ...@@ -668,6 +664,7 @@ static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
[_blurView.bottomAnchor constraintEqualToAnchor:_hostView.bottomAnchor], [_blurView.bottomAnchor constraintEqualToAnchor:_hostView.bottomAnchor],
]]; ]];
[_client setVideoChannelEnabled:NO]; [_client setVideoChannelEnabled:NO];
[_client.displayHandler destroyRendererContext];
} }
@end @end
...@@ -42,13 +42,16 @@ class CursorShapeStub; ...@@ -42,13 +42,16 @@ class CursorShapeStub;
@interface GlDisplayHandler : NSObject { @interface GlDisplayHandler : NSObject {
} }
- (void)stop; // Called once the renderer can start drawing on the view. Do nothing if the
// surface is already created.
- (void)createRendererContext:(EAGLView*)view;
// Called once the GLKView created. // Called when the renderer should stop drawing on the view. Do nothing if the
- (void)onSurfaceCreated:(EAGLView*)view; // surface is not created.
- (void)destroyRendererContext;
// Called every time the GLKView dimension is initialized or changed. // Called every time the view dimension is initialized or changed.
- (void)onSurfaceChanged:(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::RendererProxy>)CreateRendererProxy;
......
...@@ -56,9 +56,9 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate { ...@@ -56,9 +56,9 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate {
void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame, void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame,
const base::Closure& done); const base::Closure& done);
void Stop(); void CreateRendererContext(EAGLView* view);
void SurfaceCreated(EAGLView* view); void DestroyRendererContext();
void SurfaceChanged(int width, int height); void SetSurfaceSize(int width, int height);
std::unique_ptr<protocol::FrameConsumer> GrabFrameConsumer(); std::unique_ptr<protocol::FrameConsumer> GrabFrameConsumer();
...@@ -76,12 +76,13 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate { ...@@ -76,12 +76,13 @@ class Core : public protocol::CursorShapeStub, public GlRendererDelegate {
std::unique_ptr<DualBufferFrameConsumer> owned_frame_consumer_; std::unique_ptr<DualBufferFrameConsumer> owned_frame_consumer_;
base::WeakPtr<DualBufferFrameConsumer> frame_consumer_; base::WeakPtr<DualBufferFrameConsumer> frame_consumer_;
// TODO(yuweih): Release references once the surface is destroyed.
EAGLContext* eagl_context_; EAGLContext* eagl_context_;
std::unique_ptr<GlRenderer> renderer_; std::unique_ptr<GlRenderer> renderer_;
// GlDemoScreen *demo_screen_;
__weak id<GlDisplayHandlerDelegate> handler_delegate_; __weak id<GlDisplayHandlerDelegate> handler_delegate_;
// Valid only when the surface is created.
__weak EAGLView* view_;
// Used on display thread. // Used on display thread.
base::WeakPtr<Core> weak_ptr_; base::WeakPtr<Core> weak_ptr_;
base::WeakPtrFactory<Core> weak_factory_; base::WeakPtrFactory<Core> weak_factory_;
...@@ -190,21 +191,20 @@ void Core::OnSizeChanged(int width, int height) { ...@@ -190,21 +191,20 @@ void Core::OnSizeChanged(int width, int height) {
})); }));
} }
void Core::Stop() { void Core::CreateRendererContext(EAGLView* view) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
eagl_context_ = nil;
// demo_screen_ = nil;
}
void Core::SurfaceCreated(EAGLView* view) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
DCHECK(eagl_context_); DCHECK(eagl_context_);
if (view_) {
return;
}
view_ = view;
runtime_->ui_task_runner()->PostTask(FROM_HERE, base::BindBlockArc(^() { runtime_->ui_task_runner()->PostTask(FROM_HERE, base::BindBlockArc(^() {
[view startWithContext:eagl_context_]; [view startWithContext:eagl_context_];
})); }));
// TODO(yuweih): Rename methods in GlRenderer.
renderer_->OnSurfaceCreated( renderer_->OnSurfaceCreated(
std::make_unique<GlCanvas>(static_cast<int>([eagl_context_ API]))); std::make_unique<GlCanvas>(static_cast<int>([eagl_context_ API])));
...@@ -215,7 +215,22 @@ void Core::SurfaceCreated(EAGLView* view) { ...@@ -215,7 +215,22 @@ void Core::SurfaceCreated(EAGLView* view) {
frame_consumer_)); frame_consumer_));
} }
void Core::SurfaceChanged(int width, int height) { void Core::DestroyRendererContext() {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
if (!view_) {
return;
}
renderer_->OnSurfaceDestroyed();
__weak EAGLView* view = view_;
runtime_->ui_task_runner()->PostTask(FROM_HERE, base::BindBlockArc(^() {
[view stop];
}));
view_ = nil;
}
void Core::SetSurfaceSize(int width, int height) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_->OnSurfaceChanged(width, height); renderer_->OnSurfaceChanged(width, height);
} }
...@@ -250,12 +265,6 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() { ...@@ -250,12 +265,6 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() {
#pragma mark - Public #pragma mark - Public
- (void)stop {
_runtime->display_task_runner()->PostTask(
FROM_HERE,
base::Bind(&remoting::GlDisplayHandler::Core::Stop, _core->GetWeakPtr()));
}
- (std::unique_ptr<remoting::RendererProxy>)CreateRendererProxy { - (std::unique_ptr<remoting::RendererProxy>)CreateRendererProxy {
return _core->GrabRendererProxy(); return _core->GrabRendererProxy();
} }
...@@ -270,17 +279,25 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() { ...@@ -270,17 +279,25 @@ base::WeakPtr<remoting::GlDisplayHandler::Core> Core::GetWeakPtr() {
_core->GetWeakPtr(), _runtime->display_task_runner()); _core->GetWeakPtr(), _runtime->display_task_runner());
} }
- (void)onSurfaceCreated:(EAGLView*)view { - (void)createRendererContext:(EAGLView*)view {
_runtime->display_task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&remoting::GlDisplayHandler::Core::CreateRendererContext,
_core->GetWeakPtr(), view));
}
- (void)destroyRendererContext {
_runtime->display_task_runner()->PostTask( _runtime->display_task_runner()->PostTask(
FROM_HERE, base::Bind(&remoting::GlDisplayHandler::Core::SurfaceCreated, FROM_HERE,
_core->GetWeakPtr(), view)); base::BindOnce(&remoting::GlDisplayHandler::Core::DestroyRendererContext,
_core->GetWeakPtr()));
} }
- (void)onSurfaceChanged:(const CGRect&)frame { - (void)setSurfaceSize:(const CGRect&)frame {
_runtime->display_task_runner()->PostTask( _runtime->display_task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&remoting::GlDisplayHandler::Core::SurfaceChanged, base::BindOnce(&remoting::GlDisplayHandler::Core::SetSurfaceSize,
_core->GetWeakPtr(), frame.size.width, frame.size.height)); _core->GetWeakPtr(), frame.size.width, frame.size.height));
} }
#pragma mark - Properties #pragma mark - Properties
......
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