#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include <memory>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial_params.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/task/common/task_annotator.h"
#include "base/task/sequence_manager/test/fake_task.h"
#include "base/task/sequence_manager/test/sequence_manager_for_test.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "third_party/blink/public/common/input/web_touch_event.h"
#include "third_party/blink/public/common/page/launching_process_state.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/renderer/platform/scheduler/common/auto_advancing_virtual_time_domain.h"
#include "third_party/blink/renderer/platform/scheduler/common/features.h"
#include "third_party/blink/renderer/platform/scheduler/common/task_priority.h"
#include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/find_in_page_budget_pool_controller.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h"
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_queue_type.h"
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_task_queue.h"
#include "third_party/blink/renderer/platform/scheduler/test/recording_task_time_observer.h"
#include "third_party/blink/renderer/platform/scheduler/test/web_scheduling_test_helper.h"
#include "v8/include/v8.h"
TaskQueue;
namespace blink {
namespace scheduler {
namespace main_thread_scheduler_impl_unittest {
namespace {
Feature;
FakeTask;
FakeTaskTiming;
WebInputEvent;
InSequence;
Mock;
NiceMock;
NotNull;
Return;
ReturnRef;
InputEventState;
constexpr base::TimeDelta kDelayForHighPriorityRendering = …;
std::unique_ptr<PageSchedulerImpl> CreatePageScheduler(
PageScheduler::Delegate* page_scheduler_delegate,
ThreadSchedulerBase* scheduler,
AgentGroupScheduler& agent_group_scheduler) { … }
std::unique_ptr<FrameSchedulerImpl> CreateFrameScheduler(
PageSchedulerImpl* page_scheduler,
FrameScheduler::Delegate* delegate,
bool is_in_embedded_frame_tree,
FrameScheduler::FrameType frame_type) { … }
class MockFrameDelegate : public FrameScheduler::Delegate { … };
}
class FakeInputEvent : public blink::WebInputEvent { … };
class FakeTouchEvent : public blink::WebTouchEvent { … };
class FakeMouseWheelEvent : public blink::WebMouseWheelEvent { … };
void AppendToVectorTestTask(Vector<String>* vector, String value) { … }
void AppendToVectorIdleTestTask(Vector<String>* vector,
String value,
base::TimeTicks deadline) { … }
void NullTask() { … }
void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner,
Vector<int>* vector,
int* reentrant_count,
int max_reentrant_count) { … }
void IdleTestTask(int* run_count,
base::TimeTicks* deadline_out,
base::TimeTicks deadline) { … }
int g_max_idle_task_reposts = …;
void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner,
int* run_count,
base::TimeTicks deadline) { … }
void RepostingUpdateClockIdleTestTask(
SingleThreadIdleTaskRunner* idle_task_runner,
int* run_count,
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner,
base::TimeDelta advance_time,
Vector<base::TimeTicks>* deadlines,
base::TimeTicks deadline) { … }
void WillBeginFrameIdleTask(MainThreadSchedulerImpl* scheduler,
uint64_t sequence_number,
const base::TickClock* clock,
base::TimeTicks deadline) { … }
void UpdateClockToDeadlineIdleTestTask(
scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
int* run_count,
base::TimeTicks deadline) { … }
void PostingYieldingTestTask(MainThreadSchedulerImpl* scheduler,
base::SingleThreadTaskRunner* task_runner,
bool simulate_input,
bool* should_yield_before,
bool* should_yield_after) { … }
enum class SimulateInputType { … };
class MockPageSchedulerImpl : public PageSchedulerImpl { … };
class MainThreadSchedulerImplForTest : public MainThreadSchedulerImpl { … };
::std::ostream& operator<<(::std::ostream& os, const UseCase& use_case) { … }
class MainThreadSchedulerImplTest : public testing::Test { … };
class
MainThreadSchedulerImplWithLoadingPhaseBufferTimeAfterFirstMeaningfulPaintTest
: public MainThreadSchedulerImplTest,
public ::testing::WithParamInterface<bool> { … };
INSTANTIATE_TEST_SUITE_P(…);
TEST_F(MainThreadSchedulerImplTest, TestPostDefaultTask) { … }
TEST_F(MainThreadSchedulerImplTest, TestPostDefaultAndCompositor) { … }
TEST_F(MainThreadSchedulerImplTest, TestRentrantTask) { … }
TEST_F(MainThreadSchedulerImplTest, TestPostIdleTask) { … }
TEST_F(MainThreadSchedulerImplTest, TestRepostingIdleTask) { … }
TEST_F(MainThreadSchedulerImplTest, TestIdleTaskExceedsDeadline) { … }
TEST_F(MainThreadSchedulerImplTest, TestDelayedEndIdlePeriodCanceled) { … }
TEST_F(MainThreadSchedulerImplTest, TestDefaultPolicy) { … }
TEST_F(MainThreadSchedulerImplTest, TestDefaultPolicyWithSlowCompositor) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_WithoutScrollUpdates) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_WithoutPreventDefault) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_CompositorHandlesInput_LongGestureDuration) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_CompositorHandlesInput_WithoutTouchHandler) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_WithTouchHandler) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_WithoutTouchHandler) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_SingleEvent_PreventDefault) { … }
TEST_F(
MainThreadSchedulerImplTest,
TestCompositorPolicy_MainThreadHandlesInput_SingleEvent_NoPreventDefault) { … }
TEST_F(MainThreadSchedulerImplTest, Navigation_ResetsTaskCostEstimations) { … }
TEST_F(MainThreadSchedulerImplTest, TestTouchstartPolicy_Compositor) { … }
TEST_F(MainThreadSchedulerImplTest, TestTouchstartPolicy_MainThread) { … }
TEST_P(
MainThreadSchedulerImplWithLoadingPhaseBufferTimeAfterFirstMeaningfulPaintTest,
InitiallyInEarlyLoadingUseCase) { … }
TEST_P(
MainThreadSchedulerImplWithLoadingPhaseBufferTimeAfterFirstMeaningfulPaintTest,
NonOrdinaryPageDoesNotTriggerLoadingUseCase) { … }
TEST_F(MainThreadSchedulerImplTest,
EventConsumedOnCompositorThread_IgnoresMouseMove_WhenMouseUp) { … }
TEST_F(MainThreadSchedulerImplTest,
EventForwardedToMainThread_IgnoresMouseMove_WhenMouseUp) { … }
TEST_F(MainThreadSchedulerImplTest,
EventConsumedOnCompositorThread_MouseMove_WhenMouseDown) { … }
TEST_F(MainThreadSchedulerImplTest,
EventForwardedToMainThread_MouseMove_WhenMouseDown) { … }
TEST_F(MainThreadSchedulerImplTest,
EventForwardedToMainThread_MouseMove_WhenMouseDown_AfterMouseWheel) { … }
TEST_F(MainThreadSchedulerImplTest, EventForwardedToMainThread_MouseClick) { … }
TEST_F(MainThreadSchedulerImplTest,
EventConsumedOnCompositorThread_MouseWheel) { … }
TEST_F(MainThreadSchedulerImplTest,
EventForwardedToMainThread_MouseWheel_PreventDefault) { … }
TEST_F(MainThreadSchedulerImplTest,
EventForwardedToMainThread_NoPreventDefault) { … }
TEST_F(
MainThreadSchedulerImplTest,
EventForwardedToMainThreadAndBackToCompositor_MouseWheel_NoPreventDefault) { … }
TEST_F(MainThreadSchedulerImplTest,
EventConsumedOnCompositorThread_IgnoresKeyboardEvents) { … }
TEST_F(MainThreadSchedulerImplTest,
EventForwardedToMainThread_IgnoresKeyboardEvents) { … }
TEST_F(MainThreadSchedulerImplTest,
TestMainthreadScrollingUseCaseDoesNotStarveDefaultTasks) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicyEnds_CompositorHandlesInput) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicyEnds_MainThreadHandlesInput) { … }
TEST_F(MainThreadSchedulerImplTest, TestTouchstartPolicyEndsAfterTimeout) { … }
TEST_F(MainThreadSchedulerImplTest,
TestTouchstartPolicyEndsAfterConsecutiveTouchmoves) { … }
TEST_F(MainThreadSchedulerImplTest, TestShouldYield) { … }
TEST_F(MainThreadSchedulerImplTest, TestShouldYield_TouchStart) { … }
TEST_F(MainThreadSchedulerImplTest, SlowMainThreadInputEvent) { … }
TEST_F(MainThreadSchedulerImplTest, OnlyOnePendingUrgentPolicyUpdate) { … }
TEST_F(MainThreadSchedulerImplTest, OnePendingDelayedAndOneUrgentUpdatePolicy) { … }
TEST_F(MainThreadSchedulerImplTest, OneUrgentAndOnePendingDelayedUpdatePolicy) { … }
TEST_F(MainThreadSchedulerImplTest, UpdatePolicyCountTriggeredByOneInputEvent) { … }
TEST_F(MainThreadSchedulerImplTest,
UpdatePolicyCountTriggeredByThreeInputEvents) { … }
TEST_F(MainThreadSchedulerImplTest,
UpdatePolicyCountTriggeredByTwoInputEventsWithALongSeparatingDelay) { … }
TEST_F(MainThreadSchedulerImplTest, EnsureUpdatePolicyNotTriggeredTooOften) { … }
TEST_F(MainThreadSchedulerImplTest,
BlockingInputExpectedSoonWhenBlockInputEventSeen) { … }
TEST_F(MainThreadSchedulerImplTest,
BlockingInputNotExpectedSoonWhenNoBlockInputEventSeen) { … }
TEST_F(MainThreadSchedulerImplTest, TestBeginMainFrameNotExpectedUntil) { … }
TEST_F(MainThreadSchedulerImplTest, TestLongIdlePeriod) { … }
TEST_F(MainThreadSchedulerImplTest, TestLongIdlePeriodWithPendingDelayedTask) { … }
TEST_F(MainThreadSchedulerImplTest,
TestLongIdlePeriodWithLatePendingDelayedTask) { … }
TEST_F(MainThreadSchedulerImplTest, TestLongIdlePeriodRepeating) { … }
TEST_F(MainThreadSchedulerImplTest, TestLongIdlePeriodInTouchStartPolicy) { … }
TEST_F(MainThreadSchedulerImplTest, TestRendererHiddenIdlePeriod) { … }
TEST_F(MainThreadSchedulerImplTest, ThrottleableQueueEnabledByDefault) { … }
TEST_F(MainThreadSchedulerImplTest, StopAndResumeRenderer) { … }
TEST_F(MainThreadSchedulerImplTest, StopAndThrottleThrottleableQueue) { … }
TEST_F(MainThreadSchedulerImplTest, MultipleStopsNeedMultipleResumes) { … }
TEST_F(MainThreadSchedulerImplTest, PauseRenderer) { … }
TEST_F(MainThreadSchedulerImplTest, UseCaseToString) { … }
TEST_F(MainThreadSchedulerImplTest, MismatchedDidHandleInputEventOnMainThread) { … }
TEST_F(MainThreadSchedulerImplTest, BeginMainFrameOnCriticalPath) { … }
TEST_F(MainThreadSchedulerImplTest, ShutdownPreventsPostingOfNewTasks) { … }
namespace {
void SlowCountingTask(
size_t* count,
scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
int task_duration,
scoped_refptr<base::SingleThreadTaskRunner> throttleable_queue) { … }
}
TEST_F(
MainThreadSchedulerImplTest,
SYNCHRONIZED_GESTURE_ThrottleableTaskThrottling_ThrottleableQueuesStopped) { … }
TEST_F(MainThreadSchedulerImplTest,
SYNCHRONIZED_GESTURE_ThrottleableTaskThrottling_task_not_expensive) { … }
TEST_F(MainThreadSchedulerImplTest, DenyLongIdleDuringTouchStart) { … }
TEST_F(MainThreadSchedulerImplTest, SYNCHRONIZED_GESTURE_CompositingExpensive) { … }
TEST_F(MainThreadSchedulerImplTest, MAIN_THREAD_CUSTOM_INPUT_HANDLING) { … }
TEST_F(MainThreadSchedulerImplTest, MAIN_THREAD_GESTURE) { … }
class MockRAILModeObserver : public RAILModeObserver { … };
TEST_F(MainThreadSchedulerImplTest, TestResponseRAILMode) { … }
TEST_F(MainThreadSchedulerImplTest, TestAnimateRAILMode) { … }
TEST_F(MainThreadSchedulerImplTest, TestIdleRAILMode) { … }
TEST_P(
MainThreadSchedulerImplWithLoadingPhaseBufferTimeAfterFirstMeaningfulPaintTest,
TestLoadRAILMode) { … }
TEST_P(
MainThreadSchedulerImplWithLoadingPhaseBufferTimeAfterFirstMeaningfulPaintTest,
InputTerminatesLoadRAILMode) { … }
TEST_F(MainThreadSchedulerImplTest, UnthrottledTaskRunner) { … }
TEST_F(MainThreadSchedulerImplTest, EnableVirtualTime) { … }
TEST_F(MainThreadSchedulerImplTest, DisableVirtualTimeForTesting) { … }
TEST_F(MainThreadSchedulerImplTest, VirtualTimePauser) { … }
TEST_F(MainThreadSchedulerImplTest, VirtualTimePauserNonInstantTask) { … }
TEST_F(MainThreadSchedulerImplTest, VirtualTimeWithOneQueueWithoutVirtualTime) { … }
TEST_F(MainThreadSchedulerImplTest, Tracing) { … }
TEST_F(MainThreadSchedulerImplTest,
LogIpcsPostedToDocumentsInBackForwardCache) { … }
void RecordingTimeTestTask(
Vector<base::TimeTicks>* run_times,
scoped_refptr<base::TestMockTimeTaskRunner> task_runner) { … }
TEST_F(MainThreadSchedulerImplTest, LoadingControlTasks) { … }
TEST_F(MainThreadSchedulerImplTest, RequestBeginMainFrameNotExpected) { … }
TEST_F(MainThreadSchedulerImplTest,
RequestBeginMainFrameNotExpected_MultipleCalls) { … }
#if BUILDFLAG(IS_ANDROID)
TEST_F(MainThreadSchedulerImplTest, PauseTimersForAndroidWebView) {
Vector<String> run_order;
PostTestTasks(&run_order, "D1 C1 L1 I1 T1");
scheduler_->PauseTimersForAndroidWebView();
EnableIdleTasks();
test_task_runner_->FastForwardUntilNoTasksRemain();
EXPECT_THAT(run_order, testing::ElementsAre("D1", "C1", "L1", "I1"));
run_order.clear();
scheduler_->ResumeTimersForAndroidWebView();
test_task_runner_->FastForwardUntilNoTasksRemain();
EXPECT_THAT(run_order, testing::ElementsAre("T1"));
}
#endif
TEST_F(MainThreadSchedulerImplTest, FreezesCompositorQueueWhenAllPagesFrozen) { … }
class MainThreadSchedulerImplWithInitalVirtualTimeTest
: public MainThreadSchedulerImplTest { … };
TEST_F(MainThreadSchedulerImplWithInitalVirtualTimeTest, VirtualTimeOverride) { … }
TEST_F(MainThreadSchedulerImplTest, CompositingAfterInput) { … }
TEST_F(MainThreadSchedulerImplTest,
CompositorNotPrioritizedAfterContinuousInput) { … }
TEST_F(MainThreadSchedulerImplTest, TaskQueueReferenceClearedOnShutdown) { … }
TEST_F(MainThreadSchedulerImplTest, MicrotaskCheckpointTiming) { … }
TEST_F(MainThreadSchedulerImplTest, NonWakingTaskQueue) { … }
class BestEffortPriorityForFindInPageExperimentTest
: public MainThreadSchedulerImplTest { … };
TEST_F(BestEffortPriorityForFindInPageExperimentTest,
FindInPageTasksAreBestEffortPriorityUnderExperiment) { … }
TEST_F(MainThreadSchedulerImplTest, FindInPageTasksAreVeryHighPriority) { … }
TEST_F(MainThreadSchedulerImplTest, FindInPageTasksChangeToNormalPriority) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_CompositorStaysAtNormalPriority) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_FirstCompositorTaskSetToVeryHighPriority) { … }
TEST_F(MainThreadSchedulerImplTest,
TestCompositorPolicy_FirstCompositorTaskStaysAtNormalPriority) { … }
TEST_F(MainThreadSchedulerImplTest, ThrottleHandleThrottlesQueue) { … }
class PrioritizeCompositingAfterDelayTest : public MainThreadSchedulerImplTest { … };
TEST_F(PrioritizeCompositingAfterDelayTest, PreFCP) { … }
TEST_F(PrioritizeCompositingAfterDelayTest, PostFCP) { … }
TEST_F(PrioritizeCompositingAfterDelayTest, DuringCompositorGesture) { … }
struct CompositorTQPolicyDuringThreadedScrollTestParam { … };
class CompositorTQPolicyDuringThreadedScrollTest
: public MainThreadSchedulerImplTest,
public ::testing::WithParamInterface<
CompositorTQPolicyDuringThreadedScrollTestParam> { … };
TEST_P(CompositorTQPolicyDuringThreadedScrollTest, CompositorPriority) { … }
INSTANTIATE_TEST_SUITE_P(…);
TEST_F(MainThreadSchedulerImplTest, RenderBlockingTaskPriority) { … }
TEST_F(MainThreadSchedulerImplTest, RenderBlockingAndDiscreteInput) { … }
TEST_F(MainThreadSchedulerImplTest, RenderBlockingStarvationPrevention) { … }
TEST_F(MainThreadSchedulerImplTest, DetachRunningTaskQueue) { … }
class UrgentMessageSchedulingPolicyTest : public MainThreadSchedulerImplTest { … };
TEST_F(UrgentMessageSchedulingPolicyTest, PrioritizeIPCTasks) { … }
TEST_F(UrgentMessageSchedulingPolicyTest, UrgentMessageAndCompositorPriority) { … }
class DeferRendererTasksAfterInputTest
: public MainThreadSchedulerImplTest,
public ::testing::WithParamInterface<features::TaskDeferralPolicy>,
public WebSchedulingTestHelper::Delegate { … };
TEST_P(DeferRendererTasksAfterInputTest, TaskDeferral) { … }
TEST_P(DeferRendererTasksAfterInputTest, DynamicPriorityTaskDeferral) { … }
TEST_P(DeferRendererTasksAfterInputTest, TaskDeferralTimeout) { … }
TEST_P(DeferRendererTasksAfterInputTest,
DiscreteInputUseCaseDependsOnFrameRequested) { … }
TEST_P(DeferRendererTasksAfterInputTest,
DiscreteInputUseCaseIgnoresContinuous) { … }
TEST_P(DeferRendererTasksAfterInputTest, UseCaseTimeout) { … }
TEST_P(DeferRendererTasksAfterInputTest, TouchStartAndDiscreteInput) { … }
TEST_P(DeferRendererTasksAfterInputTest, DiscreteInputDuringContinuousGesture) { … }
INSTANTIATE_TEST_SUITE_P(…);
class DiscreteInputMatchesResponsivenessMetricsTest
: public MainThreadSchedulerImplTest,
public ::testing::WithParamInterface<bool> { … };
TEST_P(DiscreteInputMatchesResponsivenessMetricsTest, TestPolicy) { … }
INSTANTIATE_TEST_SUITE_P(…);
}
}
}