Skip to content

Commit a9ea7f6

Browse files
committed
[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 <[email protected]> Reviewed-by: Jamie Walch <[email protected]> Cr-Original-Commit-Position: refs/heads/master@{#551097}(cherry picked from commit 9e9ae0c) Reviewed-on: https://chromium-review.googlesource.com/1015187 Reviewed-by: Yuwei Huang <[email protected]> Cr-Commit-Position: refs/branch-heads/3396@{#61} Cr-Branched-From: 9ef2aa8-refs/heads/master@{#550428}
1 parent ce5160c commit a9ea7f6

File tree

4 files changed

+57
-40
lines changed

4 files changed

+57
-40
lines changed

remoting/client/display/gl_renderer.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ void GlRenderer::OnPixelTransformationChanged(
5353
const std::array<float, 9>& matrix) {
5454
DCHECK(thread_checker_.CalledOnValidThread());
5555
if (!canvas_) {
56-
LOG(WARNING) << "Trying to set transformation matrix when the canvas is "
57-
"not ready.";
56+
VLOG(1) << "Trying to set transformation matrix when the canvas is not "
57+
<< "ready.";
5858
return;
5959
}
6060
canvas_->SetTransformationMatrix(matrix);

remoting/ios/app/host_view_controller.mm

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ @interface HostViewController ()<ClientKeyboardDelegate,
4646
ClientGestures* _clientGestures;
4747
ClientKeyboard* _clientKeyboard;
4848
CGSize _keyboardSize;
49-
BOOL _surfaceCreated;
5049
HostSettings* _settings;
5150

5251
// Used to blur the content when the app enters background.
@@ -80,7 +79,6 @@ - (id)initWithClient:(RemotingClient*)client {
8079
if (self) {
8180
_client = client;
8281
_keyboardSize = CGSizeZero;
83-
_surfaceCreated = NO;
8482
_blocksKeyboard = NO;
8583
_settings =
8684
[[RemotingPreferences instance] settingsForHost:client.hostInfo.hostId];
@@ -197,10 +195,7 @@ - (BOOL)prefersStatusBarHidden {
197195

198196
- (void)viewDidAppear:(BOOL)animated {
199197
[super viewDidAppear:animated];
200-
if (!_surfaceCreated) {
201-
[_client.displayHandler onSurfaceCreated:_hostView];
202-
_surfaceCreated = YES;
203-
}
198+
[_client.displayHandler createRendererContext:_hostView];
204199

205200
// |_clientKeyboard| should always be the first responder even when the soft
206201
// keyboard is not visible, so that input from physical keyboard can still be
@@ -272,7 +267,7 @@ - (void)viewDidLayoutSubviews {
272267
[super viewDidLayoutSubviews];
273268

274269
// Pass the actual size of the view to the renderer.
275-
[_client.displayHandler onSurfaceChanged:_hostView.bounds];
270+
[_client.displayHandler setSurfaceSize:_hostView.bounds];
276271

277272
// Start the animation on the host's visible area.
278273
_surfaceSizeAnimationLink.paused = NO;
@@ -646,6 +641,7 @@ - (void)applicationDidBecomeActive:(UIApplication*)application {
646641
LOG(DFATAL) << "Blur view does not exist.";
647642
return;
648643
}
644+
[_client.displayHandler createRendererContext:_hostView];
649645
[_client setVideoChannelEnabled:YES];
650646
[_blurView removeFromSuperview];
651647
_blurView = nil;
@@ -668,6 +664,7 @@ - (void)applicationWillResignActive:(UIApplication*)application {
668664
[_blurView.bottomAnchor constraintEqualToAnchor:_hostView.bottomAnchor],
669665
]];
670666
[_client setVideoChannelEnabled:NO];
667+
[_client.displayHandler destroyRendererContext];
671668
}
672669

673670
@end

remoting/ios/display/gl_display_handler.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,16 @@ class CursorShapeStub;
4242
@interface GlDisplayHandler : NSObject {
4343
}
4444

45-
- (void)stop;
45+
// Called once the renderer can start drawing on the view. Do nothing if the
46+
// surface is already created.
47+
- (void)createRendererContext:(EAGLView*)view;
4648

47-
// Called once the GLKView created.
48-
- (void)onSurfaceCreated:(EAGLView*)view;
49+
// Called when the renderer should stop drawing on the view. Do nothing if the
50+
// surface is not created.
51+
- (void)destroyRendererContext;
4952

50-
// Called every time the GLKView dimension is initialized or changed.
51-
- (void)onSurfaceChanged:(const CGRect&)frame;
53+
// Called every time the view dimension is initialized or changed.
54+
- (void)setSurfaceSize:(const CGRect&)frame;
5255

5356
// Must be called immediately after the object is constructed.
5457
- (std::unique_ptr<remoting::RendererProxy>)CreateRendererProxy;

remoting/ios/display/gl_display_handler.mm

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@
5656

5757
void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame,
5858
const base::Closure& done);
59-
void Stop();
60-
void SurfaceCreated(EAGLView* view);
61-
void SurfaceChanged(int width, int height);
59+
void CreateRendererContext(EAGLView* view);
60+
void DestroyRendererContext();
61+
void SetSurfaceSize(int width, int height);
6262

6363
std::unique_ptr<protocol::FrameConsumer> GrabFrameConsumer();
6464

@@ -76,12 +76,13 @@ void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame,
7676
std::unique_ptr<DualBufferFrameConsumer> owned_frame_consumer_;
7777
base::WeakPtr<DualBufferFrameConsumer> frame_consumer_;
7878

79-
// TODO(yuweih): Release references once the surface is destroyed.
8079
EAGLContext* eagl_context_;
8180
std::unique_ptr<GlRenderer> renderer_;
82-
// GlDemoScreen *demo_screen_;
8381
__weak id<GlDisplayHandlerDelegate> handler_delegate_;
8482

83+
// Valid only when the surface is created.
84+
__weak EAGLView* view_;
85+
8586
// Used on display thread.
8687
base::WeakPtr<Core> weak_ptr_;
8788
base::WeakPtrFactory<Core> weak_factory_;
@@ -190,21 +191,20 @@ void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame,
190191
}));
191192
}
192193

193-
void Core::Stop() {
194-
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
195-
196-
eagl_context_ = nil;
197-
// demo_screen_ = nil;
198-
}
199-
200-
void Core::SurfaceCreated(EAGLView* view) {
194+
void Core::CreateRendererContext(EAGLView* view) {
201195
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
202196
DCHECK(eagl_context_);
203197

198+
if (view_) {
199+
return;
200+
}
201+
view_ = view;
202+
204203
runtime_->ui_task_runner()->PostTask(FROM_HERE, base::BindBlockArc(^() {
205204
[view startWithContext:eagl_context_];
206205
}));
207206

207+
// TODO(yuweih): Rename methods in GlRenderer.
208208
renderer_->OnSurfaceCreated(
209209
std::make_unique<GlCanvas>(static_cast<int>([eagl_context_ API])));
210210

@@ -215,7 +215,22 @@ void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame,
215215
frame_consumer_));
216216
}
217217

218-
void Core::SurfaceChanged(int width, int height) {
218+
void Core::DestroyRendererContext() {
219+
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
220+
221+
if (!view_) {
222+
return;
223+
}
224+
225+
renderer_->OnSurfaceDestroyed();
226+
__weak EAGLView* view = view_;
227+
runtime_->ui_task_runner()->PostTask(FROM_HERE, base::BindBlockArc(^() {
228+
[view stop];
229+
}));
230+
view_ = nil;
231+
}
232+
233+
void Core::SetSurfaceSize(int width, int height) {
219234
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
220235
renderer_->OnSurfaceChanged(width, height);
221236
}
@@ -250,12 +265,6 @@ - (void)dealloc {
250265

251266
#pragma mark - Public
252267

253-
- (void)stop {
254-
_runtime->display_task_runner()->PostTask(
255-
FROM_HERE,
256-
base::Bind(&remoting::GlDisplayHandler::Core::Stop, _core->GetWeakPtr()));
257-
}
258-
259268
- (std::unique_ptr<remoting::RendererProxy>)CreateRendererProxy {
260269
return _core->GrabRendererProxy();
261270
}
@@ -270,17 +279,25 @@ - (void)stop {
270279
_core->GetWeakPtr(), _runtime->display_task_runner());
271280
}
272281

273-
- (void)onSurfaceCreated:(EAGLView*)view {
282+
- (void)createRendererContext:(EAGLView*)view {
283+
_runtime->display_task_runner()->PostTask(
284+
FROM_HERE,
285+
base::BindOnce(&remoting::GlDisplayHandler::Core::CreateRendererContext,
286+
_core->GetWeakPtr(), view));
287+
}
288+
289+
- (void)destroyRendererContext {
274290
_runtime->display_task_runner()->PostTask(
275-
FROM_HERE, base::Bind(&remoting::GlDisplayHandler::Core::SurfaceCreated,
276-
_core->GetWeakPtr(), view));
291+
FROM_HERE,
292+
base::BindOnce(&remoting::GlDisplayHandler::Core::DestroyRendererContext,
293+
_core->GetWeakPtr()));
277294
}
278295

279-
- (void)onSurfaceChanged:(const CGRect&)frame {
296+
- (void)setSurfaceSize:(const CGRect&)frame {
280297
_runtime->display_task_runner()->PostTask(
281298
FROM_HERE,
282-
base::Bind(&remoting::GlDisplayHandler::Core::SurfaceChanged,
283-
_core->GetWeakPtr(), frame.size.width, frame.size.height));
299+
base::BindOnce(&remoting::GlDisplayHandler::Core::SetSurfaceSize,
300+
_core->GetWeakPtr(), frame.size.width, frame.size.height));
284301
}
285302

286303
#pragma mark - Properties

0 commit comments

Comments
 (0)