Index: components/scheduler/renderer/web_view_scheduler_impl.cc |
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.cc b/components/scheduler/renderer/web_view_scheduler_impl.cc |
index da4e80b30b6fdcd2655f330e39d74d0bfb386137..0e41a26bbf4bdaabd7fa0062a055cd9d7a4c3b00 100644 |
--- a/components/scheduler/renderer/web_view_scheduler_impl.cc |
+++ b/components/scheduler/renderer/web_view_scheduler_impl.cc |
@@ -5,6 +5,7 @@ |
#include "components/scheduler/renderer/web_view_scheduler_impl.h" |
#include "base/logging.h" |
+#include "components/scheduler/base/real_time_domain.h" |
#include "components/scheduler/base/virtual_time_domain.h" |
#include "components/scheduler/child/scheduler_tqm_delegate.h" |
#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" |
@@ -27,7 +28,8 @@ WebViewSchedulerImpl::WebViewSchedulerImpl( |
virtual_time_policy_(VirtualTimePolicy::ADVANCE), |
page_visible_(true), |
disable_background_timer_throttling_(disable_background_timer_throttling), |
- allow_virtual_time_to_advance_(true) { |
+ allow_virtual_time_to_advance_(true), |
+ have_seen_loading_task_(false) { |
renderer_scheduler->AddWebViewScheduler(this); |
} |
@@ -38,8 +40,14 @@ WebViewSchedulerImpl::~WebViewSchedulerImpl() { |
frame_scheduler->DetachFromWebViewScheduler(); |
} |
renderer_scheduler_->RemoveWebViewScheduler(this); |
- if (virtual_time_domain_) |
+ if (virtual_time_domain_) { |
+ // Since we're just about to delete virtual_time_domain_ we'd better move |
+ // the per-thread task queues back to the RealTimeDomain or we risk a UAF |
+ // when the task queues get deleted. |
+ renderer_scheduler_->SetPerThreadTaskRunnerTimeDomain( |
+ renderer_scheduler_->real_time_domain()); |
renderer_scheduler_->UnregisterTimeDomain(virtual_time_domain_.get()); |
+ } |
} |
void WebViewSchedulerImpl::setPageVisible(bool page_visible) { |
@@ -98,6 +106,10 @@ void WebViewSchedulerImpl::enableVirtualTime() { |
for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) { |
frame_scheduler->OnVirtualTimeDomainChanged(); |
} |
+ |
+ // For determinism the per-thread task queues must use virtual time too. |
+ renderer_scheduler_->SetPerThreadTaskRunnerTimeDomain( |
+ virtual_time_domain_.get()); |
} |
void WebViewSchedulerImpl::setAllowVirtualTimeToAdvance( |
@@ -119,6 +131,7 @@ bool WebViewSchedulerImpl::virtualTimeAllowedToAdvance() const { |
void WebViewSchedulerImpl::DidStartLoading(unsigned long identifier) { |
pending_loads_.insert(identifier); |
+ have_seen_loading_task_ = true; |
if (virtual_time_policy_ != |
VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING) { |
@@ -154,7 +167,11 @@ void WebViewSchedulerImpl::setVirtualTimePolicy(VirtualTimePolicy policy) { |
break; |
case VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING: |
- setAllowVirtualTimeToAdvance(pending_loads_.size() == 0); |
+ // We pause virtual time until we've seen a loading task posted, because |
+ // otherwise we could advance virtual time arbitarially far before the |
+ // first load arrives. |
+ setAllowVirtualTimeToAdvance(pending_loads_.size() == 0 && |
+ have_seen_loading_task_); |
break; |
} |
} |