Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(217)

Side by Side Diff: android_webview/browser/render_thread_manager.cc

Issue 2560463002: aw: Fix race between first frame draw and view detach causing deadlock. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « android_webview/browser/render_thread_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "android_webview/browser/render_thread_manager.h" 5 #include "android_webview/browser/render_thread_manager.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "android_webview/browser/compositor_frame_producer.h" 9 #include "android_webview/browser/compositor_frame_producer.h"
10 #include "android_webview/browser/compositor_id.h" 10 #include "android_webview/browser/compositor_id.h"
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 base::LazyInstance<internal::RequestInvokeGLTracker> 91 base::LazyInstance<internal::RequestInvokeGLTracker>
92 g_request_invoke_gl_tracker = LAZY_INSTANCE_INITIALIZER; 92 g_request_invoke_gl_tracker = LAZY_INSTANCE_INITIALIZER;
93 } 93 }
94 94
95 RenderThreadManager::RenderThreadManager( 95 RenderThreadManager::RenderThreadManager(
96 RenderThreadManagerClient* client, 96 RenderThreadManagerClient* client,
97 const scoped_refptr<base::SingleThreadTaskRunner>& ui_loop) 97 const scoped_refptr<base::SingleThreadTaskRunner>& ui_loop)
98 : ui_loop_(ui_loop), 98 : ui_loop_(ui_loop),
99 client_(client), 99 client_(client),
100 compositor_frame_producer_(nullptr), 100 compositor_frame_producer_(nullptr),
101 has_received_frame_(false),
101 renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()), 102 renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()),
102 hardware_renderer_has_frame_(false),
103 sync_on_draw_hardware_(base::CommandLine::ForCurrentProcess()->HasSwitch( 103 sync_on_draw_hardware_(base::CommandLine::ForCurrentProcess()->HasSwitch(
104 switches::kSyncOnDrawHardware)), 104 switches::kSyncOnDrawHardware)),
105 inside_hardware_release_(false), 105 inside_hardware_release_(false),
106 weak_factory_on_ui_thread_(this) { 106 weak_factory_on_ui_thread_(this) {
107 DCHECK(ui_loop_->BelongsToCurrentThread()); 107 DCHECK(ui_loop_->BelongsToCurrentThread());
108 DCHECK(client_); 108 DCHECK(client_);
109 ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr(); 109 ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr();
110 ResetRequestInvokeGLCallback(); 110 ResetRequestInvokeGLCallback();
111 } 111 }
112 112
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 176
177 gfx::Vector2d RenderThreadManager::GetScrollOffsetOnRT() { 177 gfx::Vector2d RenderThreadManager::GetScrollOffsetOnRT() {
178 base::AutoLock lock(lock_); 178 base::AutoLock lock(lock_);
179 return scroll_offset_; 179 return scroll_offset_;
180 } 180 }
181 181
182 std::unique_ptr<ChildFrame> RenderThreadManager::SetFrameOnUI( 182 std::unique_ptr<ChildFrame> RenderThreadManager::SetFrameOnUI(
183 std::unique_ptr<ChildFrame> new_frame) { 183 std::unique_ptr<ChildFrame> new_frame) {
184 DCHECK(new_frame); 184 DCHECK(new_frame);
185 base::AutoLock lock(lock_); 185 base::AutoLock lock(lock_);
186
187 has_received_frame_ = true;
boliu 2016/12/06 16:15:35 maybe add a TODO here, this doesn't work if we swi
Tobias Sargeant 2016/12/06 18:11:26 Done.
188
186 if (child_frames_.empty()) { 189 if (child_frames_.empty()) {
187 child_frames_.emplace_back(std::move(new_frame)); 190 child_frames_.emplace_back(std::move(new_frame));
188 return nullptr; 191 return nullptr;
189 } 192 }
190 std::unique_ptr<ChildFrame> uncommitted_frame; 193 std::unique_ptr<ChildFrame> uncommitted_frame;
191 if (new_frame->frame) { 194 if (new_frame->frame) {
192 // Optimization for synchronous path. 195 // Optimization for synchronous path.
193 // TODO(boliu): Remove when synchronous path is fully removed. 196 // TODO(boliu): Remove when synchronous path is fully removed.
194 DCHECK_LE(child_frames_.size(), 1u); 197 DCHECK_LE(child_frames_.size(), 1u);
195 if (!child_frames_.empty()) { 198 if (!child_frames_.empty()) {
196 uncommitted_frame = std::move(child_frames_.front()); 199 uncommitted_frame = std::move(child_frames_.front());
197 child_frames_.pop_front(); 200 child_frames_.pop_front();
198 } 201 }
199 child_frames_.emplace_back(std::move(new_frame)); 202 child_frames_.emplace_back(std::move(new_frame));
200 return uncommitted_frame; 203 return uncommitted_frame;
201 } 204 }
202 205
203 DCHECK_LE(child_frames_.size(), 2u); 206 DCHECK_LE(child_frames_.size(), 2u);
204 ChildFrameQueue pruned_frames = 207 ChildFrameQueue pruned_frames =
205 HardwareRenderer::WaitAndPruneFrameQueue(&child_frames_); 208 HardwareRenderer::WaitAndPruneFrameQueue(&child_frames_);
206 DCHECK_LE(pruned_frames.size(), 1u); 209 DCHECK_LE(pruned_frames.size(), 1u);
207 if (pruned_frames.size()) 210 if (pruned_frames.size())
208 uncommitted_frame = std::move(pruned_frames.front()); 211 uncommitted_frame = std::move(pruned_frames.front());
209 child_frames_.emplace_back(std::move(new_frame)); 212 child_frames_.emplace_back(std::move(new_frame));
210 return uncommitted_frame; 213 return uncommitted_frame;
211 } 214 }
212 215
213 ChildFrameQueue RenderThreadManager::PassFramesOnRT() { 216 ChildFrameQueue RenderThreadManager::PassFramesOnRT() {
214 base::AutoLock lock(lock_); 217 base::AutoLock lock(lock_);
215 hardware_renderer_has_frame_ =
216 hardware_renderer_has_frame_ || !child_frames_.empty();
217 ChildFrameQueue returned_frames; 218 ChildFrameQueue returned_frames;
218 returned_frames.swap(child_frames_); 219 returned_frames.swap(child_frames_);
219 return returned_frames; 220 return returned_frames;
220 } 221 }
221 222
222 ChildFrameQueue RenderThreadManager::PassUncommittedFrameOnUI() { 223 ChildFrameQueue RenderThreadManager::PassUncommittedFrameOnUI() {
223 base::AutoLock lock(lock_); 224 base::AutoLock lock(lock_);
224 for (auto& frame_ptr : child_frames_) 225 for (auto& frame_ptr : child_frames_)
225 frame_ptr->WaitOnFutureIfNeeded(); 226 frame_ptr->WaitOnFutureIfNeeded();
226 ChildFrameQueue returned_frames; 227 ChildFrameQueue returned_frames;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 !IsInsideHardwareRelease() && HasFrameForHardwareRendererOnRT()) { 328 !IsInsideHardwareRelease() && HasFrameForHardwareRendererOnRT()) {
328 hardware_renderer_.reset(new HardwareRenderer(this)); 329 hardware_renderer_.reset(new HardwareRenderer(this));
329 hardware_renderer_->CommitFrame(); 330 hardware_renderer_->CommitFrame();
330 } 331 }
331 332
332 if (draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) { 333 if (draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
333 LOG(ERROR) << "Received unexpected kModeProcessNoContext"; 334 LOG(ERROR) << "Received unexpected kModeProcessNoContext";
334 } 335 }
335 336
336 if (IsInsideHardwareRelease()) { 337 if (IsInsideHardwareRelease()) {
337 hardware_renderer_has_frame_ = false;
338 hardware_renderer_.reset(); 338 hardware_renderer_.reset();
339 // If there are no frames ready to pass to a new
340 // hardware_renderer_ then consider that equivalent to never
341 // having received a frame.
342 has_received_frame_ = HasFrameForHardwareRendererOnRT();
boliu 2016/12/06 16:15:35 I don't understand this also this means has_recei
Tobias Sargeant 2016/12/06 16:29:27 Good point about has_received_frame_. The thing I
boliu 2016/12/06 16:34:10 can you unset has_received_frame_ at end of Delete
Tobias Sargeant 2016/12/06 16:36:38 Yes. That's a much better solution.
Tobias Sargeant 2016/12/06 18:11:26 Done.
339 // Flush the idle queue in tear down. 343 // Flush the idle queue in tear down.
340 DeferredGpuCommandService::GetInstance()->PerformAllIdleWork(); 344 DeferredGpuCommandService::GetInstance()->PerformAllIdleWork();
341 return; 345 return;
342 } 346 }
343 347
344 if (draw_info->mode != AwDrawGLInfo::kModeDraw) { 348 if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
345 if (draw_info->mode == AwDrawGLInfo::kModeProcess) { 349 if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
346 DeferredGpuCommandService::GetInstance()->PerformIdleWork(true); 350 DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
347 } 351 }
348 return; 352 return;
349 } 353 }
350 354
351 if (hardware_renderer_) 355 if (hardware_renderer_)
352 hardware_renderer_->DrawGL(draw_info); 356 hardware_renderer_->DrawGL(draw_info);
353 DeferredGpuCommandService::GetInstance()->PerformIdleWork(false); 357 DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
354 } 358 }
355 359
356 void RenderThreadManager::DeleteHardwareRendererOnUI() { 360 void RenderThreadManager::DeleteHardwareRendererOnUI() {
357 DCHECK(ui_loop_->BelongsToCurrentThread()); 361 DCHECK(ui_loop_->BelongsToCurrentThread());
358 362
359 InsideHardwareReleaseReset auto_inside_hardware_release_reset(this); 363 InsideHardwareReleaseReset auto_inside_hardware_release_reset(this);
360 364
365 client_->DetachFunctorFromView();
366
361 // If the WebView gets onTrimMemory >= MODERATE twice in a row, the 2nd 367 // If the WebView gets onTrimMemory >= MODERATE twice in a row, the 2nd
362 // onTrimMemory will result in an unnecessary Render Thread InvokeGL call. 368 // onTrimMemory will result in an unnecessary Render Thread InvokeGL call.
363 bool hardware_initialized = HasFrameOnUI(); 369 if (has_received_frame_) {
364 if (hardware_initialized) { 370 // Receiving at least one frame is a precondition for
365 // The functor has only been attached to the view hierarchy if a compositor 371 // initialization (such as looing up GL bindings and constructing
366 // frame has been generated. Thus, it should only be detached in this case. 372 // hardware_renderer_).
367 client_->DetachFunctorFromView();
368
369 bool draw_functor_succeeded = client_->RequestInvokeGL(true); 373 bool draw_functor_succeeded = client_->RequestInvokeGL(true);
370 if (!draw_functor_succeeded) { 374 if (!draw_functor_succeeded) {
371 LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?"; 375 LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?";
372 // Calling release on wrong thread intentionally. 376 // Calling release on wrong thread intentionally.
373 AwDrawGLInfo info; 377 AwDrawGLInfo info;
374 info.mode = AwDrawGLInfo::kModeProcess; 378 info.mode = AwDrawGLInfo::kModeProcess;
375 DrawGL(&info); 379 DrawGL(&info);
376 } 380 }
377 } 381 }
378 382
379 GLViewRendererManager* manager = GLViewRendererManager::GetInstance(); 383 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
380 384
381 { 385 {
382 base::AutoLock lock(lock_); 386 base::AutoLock lock(lock_);
383 if (renderer_manager_key_ != manager->NullKey()) { 387 if (renderer_manager_key_ != manager->NullKey()) {
384 manager->Remove(renderer_manager_key_); 388 manager->Remove(renderer_manager_key_);
385 renderer_manager_key_ = manager->NullKey(); 389 renderer_manager_key_ = manager->NullKey();
386 } 390 }
387 } 391 }
388 392
389 if (hardware_initialized) { 393 if (has_received_frame_) {
390 // Flush any invoke functors that's caused by ReleaseHardware. 394 // Flush any invoke functors that's caused by ReleaseHardware.
391 client_->RequestInvokeGL(true); 395 client_->RequestInvokeGL(true);
392 } 396 }
393 } 397 }
394 398
395 void RenderThreadManager::SetCompositorFrameProducer( 399 void RenderThreadManager::SetCompositorFrameProducer(
396 CompositorFrameProducer* compositor_frame_producer) { 400 CompositorFrameProducer* compositor_frame_producer) {
397 DCHECK(compositor_frame_producer == compositor_frame_producer_ || 401 DCHECK(compositor_frame_producer == compositor_frame_producer_ ||
398 compositor_frame_producer_ == nullptr || 402 compositor_frame_producer_ == nullptr ||
399 compositor_frame_producer == nullptr); 403 compositor_frame_producer == nullptr);
400 compositor_frame_producer_ = compositor_frame_producer; 404 compositor_frame_producer_ = compositor_frame_producer;
401 } 405 }
402 406
403 bool RenderThreadManager::HasFrameOnUI() const { 407 bool RenderThreadManager::HasFrameOnUI() const {
404 base::AutoLock lock(lock_); 408 base::AutoLock lock(lock_);
405 return hardware_renderer_has_frame_ || !child_frames_.empty(); 409 return has_received_frame_;
406 } 410 }
407 411
408 bool RenderThreadManager::HasFrameForHardwareRendererOnRT() const { 412 bool RenderThreadManager::HasFrameForHardwareRendererOnRT() const {
409 base::AutoLock lock(lock_); 413 base::AutoLock lock(lock_);
410 return !child_frames_.empty(); 414 return !child_frames_.empty();
411 } 415 }
412 416
413 void RenderThreadManager::InitializeHardwareDrawIfNeededOnUI() { 417 void RenderThreadManager::InitializeHardwareDrawIfNeededOnUI() {
414 DCHECK(ui_loop_->BelongsToCurrentThread()); 418 DCHECK(ui_loop_->BelongsToCurrentThread());
415 GLViewRendererManager* manager = GLViewRendererManager::GetInstance(); 419 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
416 420
417 base::AutoLock lock(lock_); 421 base::AutoLock lock(lock_);
418 if (renderer_manager_key_ == manager->NullKey()) { 422 if (renderer_manager_key_ == manager->NullKey()) {
419 renderer_manager_key_ = manager->PushBack(this); 423 renderer_manager_key_ = manager->PushBack(this);
420 } 424 }
421 } 425 }
422 426
423 RenderThreadManager::InsideHardwareReleaseReset::InsideHardwareReleaseReset( 427 RenderThreadManager::InsideHardwareReleaseReset::InsideHardwareReleaseReset(
424 RenderThreadManager* render_thread_manager) 428 RenderThreadManager* render_thread_manager)
425 : render_thread_manager_(render_thread_manager) { 429 : render_thread_manager_(render_thread_manager) {
426 DCHECK(!render_thread_manager_->IsInsideHardwareRelease()); 430 DCHECK(!render_thread_manager_->IsInsideHardwareRelease());
427 render_thread_manager_->SetInsideHardwareRelease(true); 431 render_thread_manager_->SetInsideHardwareRelease(true);
428 } 432 }
429 433
430 RenderThreadManager::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() { 434 RenderThreadManager::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
431 render_thread_manager_->SetInsideHardwareRelease(false); 435 render_thread_manager_->SetInsideHardwareRelease(false);
432 } 436 }
433 437
434 } // namespace android_webview 438 } // namespace android_webview
OLDNEW
« no previous file with comments | « android_webview/browser/render_thread_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698