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:
1
AUTHORS
1
AUTHORS
@ -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) {
|
||||
|
Reference in New Issue
Block a user