0

Balance scheduler callbacks for forwarded events.

The scheduler expects balanced callbacks of DidHandleInputEventOnMainThread()
and DidHandleInputEventOnCompositorThread(EVENT_FORWARDED_TO_MAIN_THREAD).
If the expectation is broken, the wrongly-maintained UserModel would produce
an endless loop of UpdatePolicy(), which consumes device power.

Also makes corresponding changes to unit test.

Bug: 837105
Change-Id: Ib5193041728a97f055df757a33680e788dd4c876
Reviewed-on: https://chromium-review.googlesource.com/1032468
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
Commit-Queue: Dave Tapuska <dtapuska@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556077}
This commit is contained in:
Yifei Yu
2018-05-04 16:14:20 +00:00
committed by Commit Bot
parent cfb444ca0a
commit 473e303db2
5 changed files with 35 additions and 30 deletions

@ -897,6 +897,7 @@ Yeol Park <peary2@gmail.com>
Yi Shen <yi.shen@samsung.com>
Yi Sun <ratsunny@gmail.com>
Yichen Jiang <jiangyichen123@gmail.com>
Yifei Yu <yuyifei@xiaomi.com>
Yizhou Jiang <yizhou.jiang@intel.com>
Yoav Weiss <yoav@yoav.ws>
Yoav Zilberberg <yoav.zilberberg@gmail.com>

@ -49,13 +49,15 @@ class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo,
QueuedWebInputEvent(ui::WebScopedInputEvent event,
const ui::LatencyInfo& latency,
bool originally_cancelable,
HandledEventCallback callback)
HandledEventCallback callback,
bool known_by_scheduler)
: ScopedWebInputEventWithLatencyInfo(std::move(event), latency),
non_blocking_coalesced_count_(0),
creation_timestamp_(base::TimeTicks::Now()),
last_coalesced_timestamp_(creation_timestamp_),
originally_cancelable_(originally_cancelable),
callback_(std::move(callback)) {}
callback_(std::move(callback)),
known_by_scheduler_count_(known_by_scheduler ? 1 : 0) {}
~QueuedWebInputEvent() override {}
@ -83,6 +85,7 @@ class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo,
} else {
non_blocking_coalesced_count_++;
}
known_by_scheduler_count_ += other_event->known_by_scheduler_count_;
ScopedWebInputEventWithLatencyInfo::CoalesceWith(*other_event);
last_coalesced_timestamp_ = base::TimeTicks::Now();
@ -123,11 +126,10 @@ class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo,
}
}
size_t num_events_handled = 1 + blocking_coalesced_callbacks_.size();
if (queue->main_thread_scheduler_) {
// TODO(dtapuska): Change the scheduler API to take into account number of
// events processed.
for (size_t i = 0; i < num_events_handled; ++i) {
for (size_t i = 0; i < known_by_scheduler_count_; ++i) {
queue->main_thread_scheduler_->DidHandleInputEventOnMainThread(
event(), ack_result == INPUT_EVENT_ACK_STATE_CONSUMED
? blink::WebInputEventResult::kHandledApplication
@ -195,6 +197,8 @@ class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo,
bool originally_cancelable_;
HandledEventCallback callback_;
size_t known_by_scheduler_count_;
};
MainThreadEventQueue::SharedState::SharedState()
@ -298,9 +302,9 @@ void MainThreadEventQueue::HandleEvent(
event_callback = std::move(callback);
}
std::unique_ptr<QueuedWebInputEvent> queued_event(
new QueuedWebInputEvent(std::move(event), latency, originally_cancelable,
std::move(event_callback)));
std::unique_ptr<QueuedWebInputEvent> queued_event(new QueuedWebInputEvent(
std::move(event), latency, originally_cancelable,
std::move(event_callback), IsForwardedAndSchedulerKnown(ack_result)));
QueueEvent(std::move(queued_event));

@ -109,6 +109,11 @@ class CONTENT_EXPORT MainThreadEventQueue
const std::unique_ptr<MainThreadEventQueueTask>& item,
base::TimeTicks frame_time);
static bool IsForwardedAndSchedulerKnown(InputEventAckState ack_state) {
return ack_state == INPUT_EVENT_ACK_STATE_NOT_CONSUMED ||
ack_state == INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING;
}
protected:
friend class base::RefCountedThreadSafe<MainThreadEventQueue>;
virtual ~MainThreadEventQueue();

@ -257,7 +257,7 @@ TEST_F(MainThreadEventQueueTest, NonBlockingWheel) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(2);
.Times(0);
for (WebMouseWheelEvent& event : kEvents)
HandleEvent(event, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
@ -343,7 +343,7 @@ TEST_F(MainThreadEventQueueTest, NonBlockingWheel) {
TEST_F(MainThreadEventQueueTest, NonBlockingTouch) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(3);
.Times(0);
SyntheticWebTouchEvent kEvents[4];
kEvents[0].PressPoint(10, 10);
@ -448,7 +448,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouch) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(5);
.Times(3);
{
// Ensure that coalescing takes place.
HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
@ -502,7 +502,7 @@ TEST_F(MainThreadEventQueueTest, InterleavedEvents) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(2);
.Times(0);
EXPECT_FALSE(main_task_runner_->HasPendingTask());
EXPECT_EQ(0u, event_queue().size());
@ -573,7 +573,7 @@ TEST_F(MainThreadEventQueueTest, RafAlignedMouseInput) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(11);
.Times(0);
// Simulate enqueing a discrete event, followed by continuous events and
// then a discrete event. The last discrete event should flush the
@ -645,7 +645,7 @@ TEST_F(MainThreadEventQueueTest, RafAlignedTouchInput) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(10);
.Times(3);
// Simulate enqueing a discrete event, followed by continuous events and
// then a discrete event. The last discrete event should flush the
@ -782,7 +782,7 @@ TEST_F(MainThreadEventQueueTest, RafAlignedTouchInputCoalescedMoves) {
TEST_F(MainThreadEventQueueTest, RafAlignedTouchInputThrottlingMoves) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(2);
.Times(3);
SyntheticWebTouchEvent kEvents[2];
kEvents[0].PressPoint(10, 10);
@ -837,7 +837,7 @@ TEST_F(MainThreadEventQueueTest, LowLatency) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(8);
.Times(0);
for (SyntheticWebTouchEvent& event : kEvents)
HandleEvent(event, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
@ -1327,7 +1327,7 @@ TEST_F(MainThreadEventQueueTest, UnbufferedDispatchMouseEvent) {
EXPECT_CALL(renderer_scheduler_,
DidHandleInputEventOnMainThread(testing::_, testing::_))
.Times(3);
.Times(0);
HandleEvent(mouse_down, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
queue_->RequestUnbufferedInputEvents();

@ -455,21 +455,16 @@ void WidgetInputHandlerManager::DidHandleInputEventAndOverscroll(
const ui::LatencyInfo& latency_info,
std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
InputEventAckState ack_state = InputEventDispositionToAck(event_disposition);
switch (ack_state) {
case INPUT_EVENT_ACK_STATE_CONSUMED:
main_thread_scheduler_->DidHandleInputEventOnCompositorThread(
*input_event, blink::scheduler::WebMainThreadScheduler::
InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
break;
case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
case INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING:
main_thread_scheduler_->DidHandleInputEventOnCompositorThread(
*input_event, blink::scheduler::WebMainThreadScheduler::
InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
break;
default:
break;
if (ack_state == INPUT_EVENT_ACK_STATE_CONSUMED) {
main_thread_scheduler_->DidHandleInputEventOnCompositorThread(
*input_event, blink::scheduler::WebMainThreadScheduler::
InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
} else if (MainThreadEventQueue::IsForwardedAndSchedulerKnown(ack_state)) {
main_thread_scheduler_->DidHandleInputEventOnCompositorThread(
*input_event, blink::scheduler::WebMainThreadScheduler::
InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
}
if (ack_state == INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING ||
ack_state == INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING ||
ack_state == INPUT_EVENT_ACK_STATE_NOT_CONSUMED) {