diff --git a/DEPS b/DEPS index 33ee196..2f085716 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'dabdeb4d7d6bc090233f756d160a622be5266611', + 'v8_revision': '74c7e92b75798ba9d5d0b881ba4c8dcc6960f2ee', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other.
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 682944e..d68c962 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -204,6 +204,11 @@ return begin_impl_frame_tracker_.Current().frame_time; } +void Scheduler::BeginMainFrameNotExpectedUntil(base::TimeTicks time) { + TRACE_EVENT1("cc", "Scheduler::BeginMainFrameNotExpectedUntil", "time", time); + client_->ScheduledActionBeginMainFrameNotExpectedUntil(time); +} + void Scheduler::BeginImplFrameNotExpectedSoon() { compositor_timing_history_->BeginImplFrameNotExpectedSoon(); @@ -653,6 +658,11 @@ // TODO(brianderson): Pass begin_main_frame_args_ directly to client. client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_); break; + case SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT: + state_machine_.WillNotifyBeginMainFrameNotSent(); + BeginMainFrameNotExpectedUntil(begin_main_frame_args_.frame_time + + begin_main_frame_args_.interval); + break; case SchedulerStateMachine::ACTION_COMMIT: { bool commit_has_no_updates = false; state_machine_.WillCommit(commit_has_no_updates);
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index ed609b31..69bc7739 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h
@@ -48,6 +48,8 @@ virtual void ScheduledActionPerformImplSideInvalidation() = 0; virtual void DidFinishImplFrame() = 0; virtual void SendBeginMainFrameNotExpectedSoon() = 0; + virtual void ScheduledActionBeginMainFrameNotExpectedUntil( + base::TimeTicks time) = 0; protected: virtual ~SchedulerClient() {} @@ -197,6 +199,7 @@ void ScheduleBeginImplFrameDeadline(); void ScheduleBeginImplFrameDeadlineIfNeeded(); void BeginImplFrameNotExpectedSoon(); + void BeginMainFrameNotExpectedUntil(base::TimeTicks time); void SetupNextBeginFrameIfNeeded(); void StartObservingBeginFrameSource(); void StopObservingBeginFrameSource();
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 9551b43..210a2bd 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -140,6 +140,8 @@ return "ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK"; case ACTION_PERFORM_IMPL_SIDE_INVALIDATION: return "ACTION_PERFORM_IMPL_SIDE_INVALIDATION"; + case ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT: + return "ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT"; } NOTREACHED(); return "???"; @@ -190,7 +192,11 @@ "last_begin_frame_sequence_number_compositor_frame_was_fresh", last_begin_frame_sequence_number_compositor_frame_was_fresh_); state->SetBoolean("did_draw", did_draw_); - state->SetBoolean("did_send_begin_main_frame", did_send_begin_main_frame_); + state->SetBoolean("did_send_begin_main_frame_for_current_frame", + did_send_begin_main_frame_for_current_frame_); + state->SetBoolean("did_notify_begin_main_frame_not_sent", + did_notify_begin_main_frame_not_sent_); + state->SetBoolean("did_commit_during_frame", did_commit_during_frame_); state->SetBoolean("did_invalidate_compositor_frame_sink", did_invalidate_compositor_frame_sink_); state->SetBoolean("did_perform_impl_side_invalidaion", @@ -376,6 +382,42 @@ return pending_tree_is_ready_for_activation_; } +bool SchedulerStateMachine::ShouldNotifyBeginMainFrameNotSent() const { + // This method returns true if most of the conditions for sending a + // BeginMainFrame are met, but one is not actually requested. This gives the + // main thread the chance to do something else. + + // Don't notify if a BeginMainFrame has already been requested or is in + // progress. + if (needs_begin_main_frame_ || + begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) + return false; + + // Only notify when we're visible. + if (!visible_) + return false; + + // There are no BeginImplFrames while BeginFrameSource is paused, meaning + // the scheduler should send SendBeginMainFrameNotExpectedSoon instead, + // indicating a longer period of inactivity. + if (begin_frame_source_paused_) + return false; + + // Do not notify that no BeginMainFrame was sent too many times in a single + // frame. + if (did_notify_begin_main_frame_not_sent_) + return false; + + // Do not notify if a commit happened during this frame as the main thread + // will already be active and does not need to be woken up to make further + // actions. (This occurs if the main frame was scheduled but didn't complete + // before the vsync deadline). + if (did_commit_during_frame_) + return false; + + return true; +} + bool SchedulerStateMachine::CouldSendBeginMainFrame() const { if (!needs_begin_main_frame_) return false; @@ -401,7 +443,7 @@ return false; // Do not send more than one begin main frame in a begin frame. - if (did_send_begin_main_frame_) + if (did_send_begin_main_frame_for_current_frame_) return false; // Only send BeginMainFrame when there isn't another commit pending already. @@ -544,6 +586,8 @@ return ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK; if (ShouldBeginCompositorFrameSinkCreation()) return ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION; + if (ShouldNotifyBeginMainFrameNotSent()) + return ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT; return ACTION_NONE; } @@ -620,15 +664,22 @@ DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); DCHECK(visible_); DCHECK(!begin_frame_source_paused_); - DCHECK(!did_send_begin_main_frame_); + DCHECK(!did_send_begin_main_frame_for_current_frame_); begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_SENT; needs_begin_main_frame_ = false; - did_send_begin_main_frame_ = true; + did_send_begin_main_frame_for_current_frame_ = true; last_frame_number_begin_main_frame_sent_ = current_frame_number_; last_begin_frame_sequence_number_begin_main_frame_sent_ = begin_frame_sequence_number_; } +void SchedulerStateMachine::WillNotifyBeginMainFrameNotSent() { + DCHECK(visible_); + DCHECK(!begin_frame_source_paused_); + DCHECK(!did_notify_begin_main_frame_not_sent_); + did_notify_begin_main_frame_not_sent_ = true; +} + void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) { bool can_have_pending_tree = commit_has_no_updates && @@ -638,6 +689,7 @@ commit_count_++; last_commit_had_no_updates_ = commit_has_no_updates; begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; + did_commit_during_frame_ = true; if (commit_has_no_updates) { // Pending tree might still exist from prior commit. @@ -983,7 +1035,9 @@ did_submit_in_last_frame_ = false; needs_one_begin_impl_frame_ = false; - did_send_begin_main_frame_ = false; + did_notify_begin_main_frame_not_sent_ = false; + did_send_begin_main_frame_for_current_frame_ = false; + did_commit_during_frame_ = false; did_invalidate_compositor_frame_sink_ = false; did_perform_impl_side_invalidation_ = false; } @@ -1017,7 +1071,7 @@ // If we're entering a state where we won't get BeginFrames set all the // funnels so that we don't perform any actions that we shouldn't. if (!BeginFrameNeeded()) - did_send_begin_main_frame_ = true; + did_send_begin_main_frame_for_current_frame_ = true; // Synchronous compositor finishes BeginFrames before triggering their // deadline. Therefore, we update sequence numbers when becoming idle, before
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 01528b8..6656188d 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h
@@ -125,6 +125,7 @@ ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION, ACTION_PREPARE_TILES, ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK, + ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT, }; static const char* ActionToString(Action action); @@ -133,6 +134,7 @@ Action NextAction() const; void WillSendBeginMainFrame(); + void WillNotifyBeginMainFrameNotSent(); void WillCommit(bool commit_had_no_updates); void WillActivate(); void WillDraw(); @@ -320,6 +322,7 @@ bool ShouldCommit() const; bool ShouldPrepareTiles() const; bool ShouldInvalidateCompositorFrameSink() const; + bool ShouldNotifyBeginMainFrameNotSent() const; void WillDrawInternal(); void WillPerformImplSideInvalidationInternal(); @@ -363,9 +366,11 @@ // These are used to ensure that an action only happens once per frame, // deadline, etc. bool did_draw_ = false; + bool did_send_begin_main_frame_for_current_frame_ = true; // Initialized to true to prevent begin main frame before begin frames have // started. Reset to true when we stop asking for begin frames. - bool did_send_begin_main_frame_ = true; + bool did_notify_begin_main_frame_not_sent_ = true; + bool did_commit_during_frame_ = false; bool did_invalidate_compositor_frame_sink_ = false; bool did_perform_impl_side_invalidation_ = false; bool did_prepare_tiles_ = false;
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index 0a99a09..da53e5de 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -204,6 +204,10 @@ sm->WillSendBeginMainFrame(); return; + case SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT: + sm->WillNotifyBeginMainFrameNotSent(); + return; + case SchedulerStateMachine::ACTION_COMMIT: { bool commit_has_no_updates = false; sm->WillCommit(commit_has_no_updates); @@ -290,6 +294,27 @@ EXPECT_FALSE(state.BeginFrameNeeded()); } +TEST(SchedulerStateMachineTest, TestNextActionNotifyBeginMainFrameNotSent) { + SchedulerSettings default_scheduler_settings; + StateMachine state(default_scheduler_settings); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION); + state.IssueNextBeginImplFrame(); + state.CreateAndInitializeCompositorFrameSinkWithActivatedCommit(); + // A main frame was not requested so short idle work is scheduled instead. + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + + state.SetNeedsRedraw(true); + state.SetNeedsBeginMainFrame(); + // Now a main frame is requested no short idle work is scheduled. + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); +} + TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { SchedulerSettings default_scheduler_settings; @@ -309,6 +334,8 @@ EXPECT_FALSE(state.NeedsCommit()); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -458,6 +485,8 @@ // Start a frame. state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.CommitPending()); @@ -495,6 +524,8 @@ // Start a frame. state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.CommitPending()); @@ -531,6 +562,8 @@ // Verify we draw with the new frame. state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); state.SetDrawResultForTest(DRAW_SUCCESS); @@ -664,6 +697,8 @@ state.SetNeedsRedraw(true); EXPECT_TRUE(state.BeginFrameNeeded()); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_TRUE(state.RedrawPending()); @@ -700,6 +735,8 @@ // Draw the first frame. EXPECT_TRUE(state.BeginFrameNeeded()); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -716,6 +753,8 @@ // Move to another frame. This should now draw. EXPECT_TRUE(state.BeginFrameNeeded()); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE); @@ -1400,6 +1439,8 @@ EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1424,6 +1465,8 @@ // Check that the first init does not SetNeedsBeginMainFrame. state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1478,6 +1521,8 @@ // Once context recreation begins, nothing should happen. state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1528,6 +1573,8 @@ // automatically cause a redraw. EXPECT_TRUE(state.RedrawPending()); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE); @@ -1536,6 +1583,8 @@ // Next frame as no work to do. state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1544,6 +1593,8 @@ // SetCanDraw if waiting on first draw after activate. state.SetNeedsRedraw(true); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE); @@ -1636,6 +1687,8 @@ state.OnBeginImplFrame(0, 11); EXPECT_IMPL_FRAME_STATE( SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE); EXPECT_SEQUENCE_NUMBERS(11u, 10u, 10u, 10u, BeginFrameArgs::kInvalidFrameNumber); @@ -1993,7 +2046,8 @@ } void FinishPreviousCommitAndDrawWithoutExitingDeadline( - StateMachine* state_ptr) { + StateMachine* state_ptr, + bool expect_begin_main_frame_not_sent_before_impl_frame_deadline) { // Gross, but allows us to use macros below. StateMachine& state = *state_ptr; @@ -2006,6 +2060,10 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.IssueNextBeginImplFrame(); + if (expect_begin_main_frame_not_sent_before_impl_frame_deadline) { + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); + } EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); @@ -2045,7 +2103,7 @@ // Request a new commit and finish the previous one. state.SetNeedsBeginMainFrame(); - FinishPreviousCommitAndDrawWithoutExitingDeadline(&state); + FinishPreviousCommitAndDrawWithoutExitingDeadline(&state, false); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -2053,7 +2111,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Finish the previous commit and draw it. - FinishPreviousCommitAndDrawWithoutExitingDeadline(&state); + FinishPreviousCommitAndDrawWithoutExitingDeadline(&state, true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Verify we do not send another BeginMainFrame if was are submit-frame @@ -2234,6 +2292,8 @@ state.SetNeedsImplSideInvalidation(); state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( @@ -2257,6 +2317,8 @@ state.SetNeedsImplSideInvalidation(); state.IssueNextBeginImplFrame(); state.OnBeginImplFrameDeadline(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Initializing the CompositorFrameSink puts us in a state waiting for the @@ -2351,6 +2413,8 @@ state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_PERFORM_IMPL_SIDE_INVALIDATION); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Request another invalidation, which should wait until the pending tree is @@ -2399,6 +2463,8 @@ state.SetNeedsImplSideInvalidation(); state.IssueNextBeginImplFrame(); state.OnBeginImplFrameDeadline(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Ack the previous frame and begin impl frame, which should perform the @@ -2447,6 +2513,8 @@ EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_PERFORM_IMPL_SIDE_INVALIDATION); state.DidPrepareTiles(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -2473,6 +2541,8 @@ // OnBeginImplFrame() updates the sequence number. state.OnBeginImplFrame(0, 10); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_SEQUENCE_NUMBERS(10u, BeginFrameArgs::kInvalidFrameNumber, BeginFrameArgs::kInvalidFrameNumber, @@ -2500,6 +2570,8 @@ // OnBeginImplFrame() updates the sequence number. state.OnBeginImplFrame(0, 10); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_SEQUENCE_NUMBERS(10u, BeginFrameArgs::kInvalidFrameNumber, BeginFrameArgs::kInvalidFrameNumber, @@ -2583,6 +2655,8 @@ // If no further BeginMainFrame is needed, OnBeginFrameImplDeadline() // updates the pending tree's frame number. state.OnBeginImplFrame(0, 12); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_SEQUENCE_NUMBERS(12u, 10u, 10u, BeginFrameArgs::kInvalidFrameNumber, BeginFrameArgs::kInvalidFrameNumber); @@ -2644,6 +2718,8 @@ // When no updates are required, OnBeginImplFrameDeadline() updates active // tree and compositor frame freshness. state.OnBeginImplFrame(0, 15); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -2673,6 +2749,8 @@ // When the source changes, the current frame number is updated and frame // numbers for freshness are reset to invalid numbers. state.OnBeginImplFrame(1, 5); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_SEQUENCE_NUMBERS(5u, BeginFrameArgs::kInvalidFrameNumber, BeginFrameArgs::kInvalidFrameNumber,
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index b7b00127..a551f596 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -179,6 +179,11 @@ PushAction("SendBeginMainFrameNotExpectedSoon"); } + void ScheduledActionBeginMainFrameNotExpectedUntil( + base::TimeTicks time) override { + PushAction("ScheduledActionBeginMainFrameNotExpectedUntil"); + } + bool IsInsideBeginImplFrame() const { return inside_begin_impl_frame_; } base::Callback<bool(void)> InsideBeginImplFrame(bool state) { @@ -485,12 +490,14 @@ EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // WillBeginImplFrame is responsible for sending BeginFrames to video. - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); client_->Reset(); scheduler_->SetVideoNeedsBeginFrames(false); @@ -541,7 +548,8 @@ // BeginImplFrame should prepare the draw. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -556,7 +564,8 @@ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) // to avoid excessive toggles. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -976,7 +985,8 @@ // the deadline task. client->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // On the deadline, the actions should have occured in the right order. @@ -1003,7 +1013,8 @@ // the deadline task. client->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // Draw. The draw will trigger SetNeedsPrepareTiles, and @@ -1023,7 +1034,8 @@ // We need a BeginImplFrame where we don't swap to go idle. client->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. @@ -1044,7 +1056,8 @@ // BeginImplFrame. There will be no draw, only PrepareTiles. client->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. @@ -1065,7 +1078,8 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->PrepareTilesPending()); @@ -1087,7 +1101,8 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -1109,7 +1124,8 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->PrepareTilesPending()); @@ -1133,7 +1149,8 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->PrepareTilesPending()); @@ -1151,7 +1168,8 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -1177,7 +1195,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -1196,7 +1215,8 @@ client_->Reset(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // No scheduled prepare tiles because we've already counted a prepare tiles in @@ -1209,7 +1229,8 @@ client_->Reset(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // Resume scheduled prepare tiles. @@ -1697,8 +1718,9 @@ scheduler_->SetNeedsRedraw(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_ACTION("AddObserver(this)", client_, 0, 2); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2); + EXPECT_ACTION("AddObserver(this)", client_, 0, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); client_->Reset(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); @@ -1730,7 +1752,9 @@ client_->Reset(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, + 2); client_->Reset(); // Deadline should be immediate. @@ -2108,7 +2132,7 @@ // NotifyReadyToCommit should trigger the commit. scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); scheduler_->NotifyReadyToCommit(); - EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_); + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1); client_->Reset(); // NotifyReadyToActivate should trigger the activation. @@ -2119,8 +2143,9 @@ // BeginImplFrame deadline should draw. The following BeginImplFrame deadline // should SetNeedsBeginFrame(false) to avoid excessive toggles. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 2); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); client_->Reset(); // Make sure SetNeedsBeginFrame isn't called on the client @@ -2371,7 +2396,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2532,7 +2558,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -2546,7 +2573,8 @@ // Unthrottled frame source will immediately begin a new frame. task_runner().RunPendingTasks(); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2568,7 +2596,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); // Switch to an unthrottled frame source before the frame deadline is hit. scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get()); @@ -2579,9 +2608,10 @@ client_->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 2); + EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 3); // Unthrottled frame source will immediately begin a new frame. - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); scheduler_->SetNeedsRedraw(); client_->Reset(); @@ -2601,7 +2631,8 @@ client_->Reset(); task_runner().RunPendingTasks(); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2621,7 +2652,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -2637,7 +2669,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); client_->Reset(); // Switch to a null frame source. @@ -2734,6 +2767,23 @@ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2); } +// Tests to ensure that we send a ScheduledActionBeginMainFrameNotExpectedUntil +// when expected. +TEST_F(SchedulerTest, ScheduledActionBeginMainFrameNotExpectedUntil) { + SetUpScheduler(EXTERNAL_BFS); + + scheduler_->SetNeedsRedraw(); + EXPECT_ACTION("AddObserver(this)", client_, 0, 1); + client_->Reset(); + + EXPECT_SCOPED(AdvanceFrame()); + task_runner().RunPendingTasks(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 2, 3); + client_->Reset(); +} + // Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected. TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) { SetUpScheduler(EXTERNAL_BFS); @@ -2759,7 +2809,8 @@ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) // and send a SendBeginMainFrameNotExpectedSoon. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2784,8 +2835,9 @@ // Next vsync. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 2, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 3); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2803,8 +2855,9 @@ // Next vsync. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2817,9 +2870,10 @@ // Idle on next vsync, as the animation has completed. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3); - EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4); + EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); client_->Reset(); } @@ -2838,9 +2892,10 @@ // Idle on next vsync. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3); - EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4); + EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); client_->Reset(); } @@ -2860,7 +2915,8 @@ // Next vsync, the first requested frame happens. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2869,7 +2925,8 @@ // Next vsync, the second requested frame happens (the one requested inside // the previous frame's begin impl frame step). EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2930,7 +2987,7 @@ fake_external_begin_frame_source_->LastAckForObserver(scheduler_.get())); scheduler_->NotifyReadyToCommit(); - EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_); + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -2939,8 +2996,9 @@ // Next vsync. args = SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2964,9 +3022,10 @@ // Idle on next vsync. args = SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3); - EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4); + EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -3047,8 +3106,9 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); client_->Reset(); // Android onDraw. @@ -3073,9 +3133,10 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); EXPECT_FALSE(scheduler_->PrepareTilesPending()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3); - EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4); + EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4); EXPECT_FALSE(scheduler_->begin_frames_expected()); client_->Reset(); } @@ -3090,8 +3151,9 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); client_->Reset(); // Android onDraw. @@ -3119,8 +3181,9 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3); client_->Reset(); // Android onDraw. @@ -3255,7 +3318,8 @@ scheduler_->SetNeedsImplSideInvalidation(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); // Deadline. client_->Reset(); @@ -3421,7 +3485,8 @@ BeginFrameArgs args = SendNextBeginFrame(); EXPECT_LT(latest_confirmed_sequence_number, args.sequence_number); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -3447,7 +3512,8 @@ args = SendNextBeginFrame(); EXPECT_LT(latest_confirmed_sequence_number, args.sequence_number); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -3482,7 +3548,8 @@ client_->Reset(); BeginFrameArgs args = SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -3529,7 +3596,8 @@ client_->Reset(); SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // Until tiles were prepared, further proactive BeginFrames are expected. EXPECT_TRUE(scheduler_->begin_frames_expected()); @@ -3573,7 +3641,8 @@ // First BeginFrame is handled by StateMachine. BeginFrameArgs first_args = SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); // State machine is no longer interested in BeginFrames, but scheduler is // still observing the source. @@ -3654,7 +3723,8 @@ source_id, 1, now_src()); fake_external_begin_frame_source_->TestOnBeginFrame(args); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -3714,7 +3784,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); // Do not run pending deadline but send a new begin frame. The begin frame is // saved and run when the previous frame is over. @@ -3728,7 +3799,8 @@ // The saved begin frame is posted as a task. client_->Reset(); task_runner_->RunPendingTasks(); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); } TEST_F(SchedulerTest, IncomingBeginFrameReplacesSavedBeginFrame) { @@ -3738,7 +3810,8 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); // Send two BeginFrames while deadline is pending. client_->Reset(); @@ -3754,7 +3827,8 @@ // Only the last BeginFrame runs. client_->Reset(); task_runner_->RunPendingTasks(); - EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2); client_->Reset(); task_runner_->RunPendingTasks();
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index b07d78d..999be132 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -364,6 +364,7 @@ void BeginMainFrameNotExpectedSoon() override { test_hooks_->BeginMainFrameNotExpectedSoon(); } + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {} bool IsForSubframe() override { return false; }
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h index 065f692..948e5b2 100644 --- a/cc/test/stub_layer_tree_host_client.h +++ b/cc/test/stub_layer_tree_host_client.h
@@ -18,6 +18,7 @@ void DidBeginMainFrame() override {} void BeginMainFrame(const BeginFrameArgs& args) override {} void BeginMainFrameNotExpectedSoon() override {} + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {} void UpdateLayerTreeHost() override {} void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, const gfx::Vector2dF& outer_delta,
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 11a354a..7abf735a 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -247,6 +247,10 @@ client_->BeginMainFrameNotExpectedSoon(); } +void LayerTreeHost::BeginMainFrameNotExpectedUntil(base::TimeTicks time) { + client_->BeginMainFrameNotExpectedUntil(time); +} + void LayerTreeHost::BeginMainFrame(const BeginFrameArgs& args) { client_->BeginMainFrame(args); }
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 9ecdc77..3919895 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -387,6 +387,7 @@ void DidBeginMainFrame(); void BeginMainFrame(const BeginFrameArgs& args); void BeginMainFrameNotExpectedSoon(); + void BeginMainFrameNotExpectedUntil(base::TimeTicks time); void AnimateLayers(base::TimeTicks monotonic_frame_begin_time); void RequestMainFrameUpdate(); void FinishCommitOnImplThread(LayerTreeHostImpl* host_impl);
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h index 84416d6..f54a69b0 100644 --- a/cc/trees/layer_tree_host_client.h +++ b/cc/trees/layer_tree_host_client.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/memory/ref_counted.h" +#include "base/time/time.h" namespace gfx { class Vector2dF; @@ -24,6 +25,7 @@ // mode, this corresponds to DidCommit(). virtual void BeginMainFrame(const BeginFrameArgs& args) = 0; virtual void BeginMainFrameNotExpectedSoon() = 0; + virtual void BeginMainFrameNotExpectedUntil(base::TimeTicks time) = 0; virtual void DidBeginMainFrame() = 0; // A LayerTreeHost is bound to a LayerTreeHostClient. Visual frame-based // updates to the state of the LayerTreeHost are expected to happen only in
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc index 48d1902..3d3b4a6 100644 --- a/cc/trees/proxy_impl.cc +++ b/cc/trees/proxy_impl.cc
@@ -612,6 +612,14 @@ proxy_main_weak_ptr_)); } +void ProxyImpl::ScheduledActionBeginMainFrameNotExpectedUntil( + base::TimeTicks time) { + DCHECK(IsImplThread()); + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ProxyMain::BeginMainFrameNotExpectedUntil, + proxy_main_weak_ptr_, time)); +} + DrawResult ProxyImpl::DrawInternal(bool forced_draw) { TRACE_EVENT_SYNTHETIC_DELAY("cc.Draw");
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h index e80a118..46071cdd 100644 --- a/cc/trees/proxy_impl.h +++ b/cc/trees/proxy_impl.h
@@ -108,6 +108,8 @@ void ScheduledActionInvalidateCompositorFrameSink() override; void ScheduledActionPerformImplSideInvalidation() override; void SendBeginMainFrameNotExpectedSoon() override; + void ScheduledActionBeginMainFrameNotExpectedUntil( + base::TimeTicks time) override; DrawResult DrawInternal(bool forced_draw);
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc index 43f6fc3..8632105c 100644 --- a/cc/trees/proxy_main.cc +++ b/cc/trees/proxy_main.cc
@@ -75,6 +75,12 @@ layer_tree_host_->BeginMainFrameNotExpectedSoon(); } +void ProxyMain::BeginMainFrameNotExpectedUntil(base::TimeTicks time) { + TRACE_EVENT0("cc", "ProxyMain::BeginMainFrameNotExpectedUntil"); + DCHECK(IsMainThread()); + layer_tree_host_->BeginMainFrameNotExpectedUntil(time); +} + void ProxyMain::DidCommitAndDrawFrame() { DCHECK(IsMainThread()); layer_tree_host_->DidCommitAndDrawFrame();
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h index 9fb7823d..e4ab354 100644 --- a/cc/trees/proxy_main.h +++ b/cc/trees/proxy_main.h
@@ -42,6 +42,7 @@ void DidReceiveCompositorFrameAck(); void BeginMainFrameNotExpectedSoon(); + void BeginMainFrameNotExpectedUntil(base::TimeTicks time); void DidCommitAndDrawFrame(); void SetAnimationEvents(std::unique_ptr<MutatorEvents> events); void DidLoseCompositorFrameSink();
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 29821e38..777df13f 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -632,6 +632,11 @@ layer_tree_host_->BeginMainFrameNotExpectedSoon(); } +void SingleThreadProxy::ScheduledActionBeginMainFrameNotExpectedUntil( + base::TimeTicks time) { + layer_tree_host_->BeginMainFrameNotExpectedUntil(time); +} + void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs& begin_frame_args) { if (scheduler_on_impl_thread_) { scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 4cbb14a..54e01cfd 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h
@@ -72,6 +72,8 @@ void ScheduledActionInvalidateCompositorFrameSink() override; void ScheduledActionPerformImplSideInvalidation() override; void SendBeginMainFrameNotExpectedSoon() override; + void ScheduledActionBeginMainFrameNotExpectedUntil( + base::TimeTicks time) override; // LayerTreeHostImplClient implementation void DidLoseCompositorFrameSinkOnImplThread() override;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index 8c46a21..eb4121a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -46,11 +46,11 @@ import org.chromium.chrome.browser.init.BrowserParts; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; import org.chromium.chrome.browser.init.EmptyBrowserParts; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.util.IntentUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java index db8c414e..3ed7c9e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java
@@ -10,11 +10,11 @@ import org.chromium.base.ContextUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; /** * Manages the notification indicating that there are incognito tabs opened in Document mode.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java index dddd8ef..903ce8c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -53,7 +53,7 @@ import org.chromium.chrome.browser.metrics.UmaUtils; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; -import org.chromium.chrome.browser.notifications.ChannelsUpdater; +import org.chromium.chrome.browser.notifications.channels.ChannelsUpdater; import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java index dec18c4..a7507873 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
@@ -17,10 +17,10 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.chrome.R; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java index 029c636..3eca3e9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
@@ -42,11 +42,11 @@ import org.chromium.blink.mojom.MediaSessionAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.AppHooks; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.content_public.common.MediaMetadata; import java.util.ArrayList;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java index e407791..a1f6265 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -24,6 +24,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.R; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.ui.base.LocalizationUtils; import java.util.Date;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java index 43f90b62..c6794917 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java
@@ -10,6 +10,8 @@ import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; +import org.chromium.chrome.browser.notifications.channels.ChannelsInitializer; /** * Factory which supplies the appropriate type of notification builder based on Android version.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderForO.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderForO.java index 6a4ce4cc..f4423670 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderForO.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderForO.java
@@ -10,6 +10,8 @@ import org.chromium.base.BuildInfo; import org.chromium.base.Log; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; +import org.chromium.chrome.browser.notifications.channels.ChannelsInitializer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java index 150862b..5070fedc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java
@@ -6,6 +6,8 @@ import android.app.Notification; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; + import java.util.List; /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java index f255ca1..f9f8e5a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java
@@ -10,6 +10,7 @@ import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.Log; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java index 2eb51fec..bbb20d278 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -31,6 +31,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.Preferences; import org.chromium.chrome.browser.preferences.PreferencesLauncher;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java index 312d43d..06b8dbb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -15,6 +15,7 @@ import org.chromium.base.Log; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java index 702decb3..171b7b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
@@ -8,6 +8,8 @@ import android.content.Context; import android.os.Build; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; + /** * Builds a notification using the standard Notification.BigTextStyle layout. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelDefinitions.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java similarity index 96% rename from chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelDefinitions.java rename to chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java index 8e66a2e..81976b4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelDefinitions.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.notifications.channels; import android.annotation.TargetApi; import android.app.NotificationManager; @@ -137,10 +137,10 @@ public static class Channel { @ChannelId public final String mId; - final int mNameResId; - final int mImportance; + public final int mNameResId; + public final int mImportance; @ChannelGroupId - final String mGroupId; + public final String mGroupId; Channel(@ChannelId String id, int nameResId, int importance, @ChannelGroupId String groupId) { @@ -156,8 +156,8 @@ */ public static class ChannelGroup { @ChannelGroupId - final String mId; - final int mNameResId; + public final String mId; + public final int mNameResId; ChannelGroup(@ChannelGroupId String id, int nameResId) { this.mId = id;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelsInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java similarity index 94% rename from chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelsInitializer.java rename to chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java index 299189c..d7a9d36a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelsInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java
@@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.notifications.channels; + +import org.chromium.chrome.browser.notifications.NotificationManagerProxy; /** * Initializes our notification channels. */ public class ChannelsInitializer { - private final NotificationManagerProxy mNotificationManager; private final ChannelDefinitions mChannelDefinitions; @@ -57,5 +58,4 @@ mChannelDefinitions.getChannelGroupFromId(channel)); mNotificationManager.createNotificationChannel(channel); } - }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelsUpdater.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java similarity index 95% rename from chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelsUpdater.java rename to chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java index 8a7a1a95..cbec962 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChannelsUpdater.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.notifications.channels; import android.app.NotificationManager; import android.content.Context; @@ -11,6 +11,7 @@ import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl; /** * Contains helper methods for checking if we should update channels and updating them if so.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java index 7f95393a..5c4e7bd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java
@@ -24,10 +24,10 @@ import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.document.ChromeLauncherActivity; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAction; import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationOptOut;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBroadcastService.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBroadcastService.java index bf83d6a..6382d933 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBroadcastService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBroadcastService.java
@@ -20,13 +20,13 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.chrome.R; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.notifications.NotificationManagerProxy; import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.util.IntentUtils; /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java index ea8a1d5..5b58733 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
@@ -16,13 +16,13 @@ import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.notifications.NotificationManagerProxy; import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.preferences.PreferencesLauncher; import org.chromium.components.sync.AndroidSyncSettings;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java index 872c4bb..f8126f7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java
@@ -10,7 +10,7 @@ import android.os.AsyncTask; import org.chromium.base.BuildInfo; -import org.chromium.chrome.browser.notifications.ChannelsUpdater; +import org.chromium.chrome.browser.notifications.channels.ChannelsUpdater; /** * Triggered when Chrome's package is replaced (e.g. when it is upgraded).
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 918e0ef5..a9deeb4 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -574,9 +574,6 @@ "java/src/org/chromium/chrome/browser/nfc/BeamController.java", "java/src/org/chromium/chrome/browser/nfc/BeamProvider.java", "java/src/org/chromium/chrome/browser/notifications/ActionInfo.java", - "java/src/org/chromium/chrome/browser/notifications/ChannelDefinitions.java", - "java/src/org/chromium/chrome/browser/notifications/ChannelsInitializer.java", - "java/src/org/chromium/chrome/browser/notifications/ChannelsUpdater.java", "java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java", "java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java", "java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java", @@ -594,6 +591,9 @@ "java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java", "java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java", "java/src/org/chromium/chrome/browser/notifications/WebApkNotificationClient.java", + "java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java", + "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java", + "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java", "java/src/org/chromium/chrome/browser/ntp/ChromeHomeIncognitoNewTabPage.java", "java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPage.java", "java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java", @@ -1695,10 +1695,10 @@ "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestTabHolder.java", "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTitleUpdatedTest.java", "junit/src/org/chromium/chrome/browser/metrics/VariationsSessionTest.java", - "junit/src/org/chromium/chrome/browser/notifications/ChannelDefinitionsTest.java", - "junit/src/org/chromium/chrome/browser/notifications/ChannelsInitializerTest.java", - "junit/src/org/chromium/chrome/browser/notifications/ChannelsUpdaterTest.java", "junit/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeUnitTest.java", + "junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java", + "junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java", + "junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java", "junit/src/org/chromium/chrome/browser/ntp/NativePageFactoryTest.java", "junit/src/org/chromium/chrome/browser/ntp/TitleUtilTest.java", "junit/src/org/chromium/chrome/browser/ntp/cards/ContentSuggestionsUnitTestUtils.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 476fc94..83646723 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1477,6 +1477,7 @@ @SmallTest @RetryOnFailure @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testPostMessageThroughHiddenTabWithRequestBeforeMayLaunchUrl() throws InterruptedException { sendPostMessageDuringHiddenTabTransition(BEFORE_MAY_LAUNCH_URL); @@ -1489,6 +1490,7 @@ @SmallTest @RetryOnFailure @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testPostMessageThroughHiddenTabWithRequestBeforeIntent() throws InterruptedException { sendPostMessageDuringHiddenTabTransition(BEFORE_INTENT); @@ -1501,11 +1503,13 @@ @SmallTest @RetryOnFailure @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testPostMessageThroughHiddenTabWithRequestAfterIntent() throws InterruptedException { sendPostMessageDuringHiddenTabTransition(AFTER_INTENT); } + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) private void sendPostMessageDuringHiddenTabTransition(int requestTime) throws InterruptedException { sendPostMessageDuringSpeculationTransition( @@ -1788,6 +1792,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabAndChangingFragmentIgnoreFragments() throws Exception { startHiddenTabAndChangeFragment(true, true); } @@ -1796,6 +1801,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabAndChangingFragmentDontIgnoreFragments() throws Exception { startHiddenTabAndChangeFragment(false, true); } @@ -1804,6 +1810,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabAndChangingFragmentDontWait() throws Exception { startHiddenTabAndChangeFragment(true, false); } @@ -1812,6 +1819,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabAndChangingFragmentDontWaitDrop() throws Exception { startHiddenTabAndChangeFragment(false, false); } @@ -1900,6 +1908,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabCorrectUrl() throws Exception { testSpeculateCorrectUrl(CustomTabsConnection.SpeculationParams.HIDDEN_TAB); } @@ -2105,6 +2114,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabWithReferrer() throws Exception { testSpeculatingWithReferrer(CustomTabsConnection.SpeculationParams.HIDDEN_TAB); } @@ -2143,6 +2153,7 @@ @SmallTest @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @RetryOnFailure + @CommandLineFlags.Add("enable-features=" + ChromeFeatureList.CCT_BACKGROUND_TAB) public void testHiddenTabWithMismatchedReferrers() throws Exception { testSpeculatingWithMismatchedReferrers(CustomTabsConnection.SpeculationParams.HIDDEN_TAB); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java index 612b579..52486de 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java
@@ -32,8 +32,8 @@ import org.chromium.base.BaseChromiumApplication; import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.content_public.common.MediaMetadata; import org.chromium.testing.local.LocalRobolectricTestRunner;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelDefinitionsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java similarity index 93% rename from chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelDefinitionsTest.java rename to chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java index 26e4098..ff933a0 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelDefinitionsTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.notifications.channels; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.everyItem;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelsInitializerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java similarity index 99% rename from chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelsInitializerTest.java rename to chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java index af09641..75fd5f4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelsInitializerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.notifications.channels; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.empty;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelsUpdaterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java similarity index 98% rename from chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelsUpdaterTest.java rename to chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java index 03f85d0..43f7050 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/ChannelsUpdaterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.notifications.channels; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder;
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 9b02091c..49c2b8c 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -66,6 +66,7 @@ #include "components/spellcheck/spellcheck_build_features.h" #include "components/ssl_config/ssl_config_switches.h" #include "components/strings/grit/components_strings.h" +#include "components/suggestions/features.h" #include "components/sync/driver/sync_driver_switches.h" #include "components/tracing/common/tracing_switches.h" #include "components/translate/core/browser/translate_infobar_delegate.h" @@ -2832,6 +2833,11 @@ SINGLE_VALUE_TYPE(switches::kShowCertLink)}, #endif + {"use-suggestions-even-if-few", + flag_descriptions::kUseSuggestionsEvenIfFewFeatureName, + flag_descriptions::kUseSuggestionsEvenIfFewFeatureDescription, kOsAll, + FEATURE_VALUE_TYPE(suggestions::kUseSuggestionsEvenIfFewFeature)}, + // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index e4b046c..bec06f4 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -115,7 +115,7 @@ base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kCCTBackgroundTab{"CCTBackgroundTab", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kCCTExternalLinkHandling{"CCTExternalLinkHandling", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 6df250b..1ae79da2 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -3139,7 +3139,13 @@ TestHelper("testFindAPI", "web_view/shim", NO_TEST_SERVER); } -IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_TestFindAPI_findupdate) { +// crbug.com/710486 +#if defined(MEMORY_SANITIZER) +#define MAYBE_Shim_TestFindAPI_findupdate DISABLED_Shim_TestFindAPI_findupdate +#else +#define MAYBE_Shim_TestFindAPI_findupdate Shim_TestFindAPI_findupdate +#endif +IN_PROC_BROWSER_TEST_P(WebViewTest, MAYBE_Shim_TestFindAPI_findupdate) { TestHelper("testFindAPI_findupdate", "web_view/shim", NO_TEST_SERVER); }
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 48e50e0..5caa2b0a 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3115,4 +3115,11 @@ const char kEnableHeapProfilingTaskProfiler[] = "Enabled (task mode)"; +const char kUseSuggestionsEvenIfFewFeatureName[] = + "Disable minimum for server-side tile suggestions on NTP."; + +const char kUseSuggestionsEvenIfFewFeatureDescription[] = + "Request server-side suggestions even if there are only very few of them " + "and use them for tiles on the New Tab Page."; + } // namespace flag_descriptions
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f8dd1a1..e144fb0 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -3384,6 +3384,11 @@ extern const char kEnableHeapProfilingModeNative[]; extern const char kEnableHeapProfilingTaskProfiler[]; +// Name and description of the flag allowing the usage of a small set of +// server-side suggestions in NTP tiles. +extern const char kUseSuggestionsEvenIfFewFeatureName[]; +extern const char kUseSuggestionsEvenIfFewFeatureDescription[]; + } // namespace flag_descriptions #endif // CHROME_BROWSER_FLAG_DESCRIPTIONS_H_
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java index f886479..25e43b42 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java
@@ -6,8 +6,8 @@ import android.app.Notification; -import org.chromium.chrome.browser.notifications.ChannelDefinitions; import org.chromium.chrome.browser.notifications.NotificationManagerProxy; +import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import java.util.ArrayList; import java.util.Iterator;
diff --git a/components/payments/mojom/payment_app.mojom b/components/payments/mojom/payment_app.mojom index 1b9ee5c7..b43c771 100644 --- a/components/payments/mojom/payment_app.mojom +++ b/components/payments/mojom/payment_app.mojom
@@ -58,6 +58,8 @@ => (PaymentHandlerStatus status); SetPaymentInstrument(string instrument_key, PaymentInstrument instrument) => (PaymentHandlerStatus status); + ClearPaymentInstruments() + => (PaymentHandlerStatus status); }; struct PaymentAppRequest {
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java index 5a6bd92..331328a 100644 --- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java +++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
@@ -42,10 +42,6 @@ private final Context mContext; private final Set<AccountHolder> mAccounts = new HashSet<>(); - // Tracks the number of in-progress getAccountsByType() tasks so that tests can wait for - // their completion. - private final ZeroCounter mGetAccountsTaskCounter = new ZeroCounter(); - @VisibleForTesting public FakeAccountManagerDelegate(Context context, Account... accounts) { mContext = context; @@ -70,12 +66,6 @@ return validAccounts.toArray(new Account[0]); } - @VisibleForTesting - public void waitForGetAccountsTask() throws InterruptedException { - // Wait until all tasks are done because we don't know which is being waited for. - mGetAccountsTaskCounter.waitUntilZero(); - } - /** * Add an AccountHolder directly. * @@ -177,36 +167,4 @@ } throw new IllegalArgumentException("Can not find AccountHolder for account " + account); } - - /** - * Simple concurrency helper class for waiting until a resource count becomes zero. - */ - private static class ZeroCounter { - private static final int WAIT_TIMEOUT_MS = 10000; - - private final Object mLock = new Object(); - private int mCount = 0; - - public void increment() { - synchronized (mLock) { - mCount++; - } - } - - public void decrement() { - synchronized (mLock) { - if (--mCount == 0) { - mLock.notifyAll(); - } - } - } - - public void waitUntilZero() throws InterruptedException { - synchronized (mLock) { - while (mCount != 0) { - mLock.wait(WAIT_TIMEOUT_MS); - } - } - } - } }
diff --git a/components/subresource_filter/core/common/BUILD.gn b/components/subresource_filter/core/common/BUILD.gn index eed0e8a..6c1ce856 100644 --- a/components/subresource_filter/core/common/BUILD.gn +++ b/components/subresource_filter/core/common/BUILD.gn
@@ -34,6 +34,8 @@ "unindexed_ruleset.h", "url_pattern.cc", "url_pattern.h", + "url_pattern_index.cc", + "url_pattern_index.h", ] public_deps = [ @@ -57,10 +59,13 @@ "test_ruleset_creator.h", "test_ruleset_utils.cc", "test_ruleset_utils.h", + "url_rule_test_support.cc", + "url_rule_test_support.h", ] deps = [ ":common", "//base", + "//net", "//testing/gtest", "//third_party/protobuf:protobuf_lite", ]
diff --git a/components/subresource_filter/core/common/PRESUBMIT.py b/components/subresource_filter/core/common/PRESUBMIT.py index bb1e72c..7e05408 100644 --- a/components/subresource_filter/core/common/PRESUBMIT.py +++ b/components/subresource_filter/core/common/PRESUBMIT.py
@@ -26,7 +26,8 @@ continue basename = input_api.basename(path) - if basename.endswith('.fbs') or basename == 'indexed_ruleset.cc': + if (basename == 'indexed_ruleset.cc' or basename == 'url_pattern_index.cc' + or basename.endswith('.fbs')): indexed_ruleset_changed = True if basename == 'indexed_ruleset.cc': for (_, line) in affected_file.ChangedContents():
diff --git a/components/subresource_filter/core/common/document_subresource_filter_unittest.cc b/components/subresource_filter/core/common/document_subresource_filter_unittest.cc index 7156236..f447177 100644 --- a/components/subresource_filter/core/common/document_subresource_filter_unittest.cc +++ b/components/subresource_filter/core/common/document_subresource_filter_unittest.cc
@@ -11,6 +11,8 @@ #include "components/subresource_filter/core/common/test_ruleset_creator.h" #include "components/subresource_filter/core/common/test_ruleset_utils.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" +#include "url/origin.h" namespace subresource_filter { @@ -163,7 +165,7 @@ activation_state.generic_blocking_rules_disabled = generic_blocking_rules_disabled; return activation_state; - }; + } const MemoryMappedRuleset* ruleset() { return ruleset_.get(); }
diff --git a/components/subresource_filter/core/common/flat/BUILD.gn b/components/subresource_filter/core/common/flat/BUILD.gn index 195c0cd1..d554b35 100644 --- a/components/subresource_filter/core/common/flat/BUILD.gn +++ b/components/subresource_filter/core/common/flat/BUILD.gn
@@ -6,6 +6,7 @@ flatbuffer("flatbuffer") { sources = [ - "rules.fbs", + "indexed_ruleset.fbs", + "url_pattern_index.fbs", ] }
diff --git a/components/subresource_filter/core/common/flat/indexed_ruleset.fbs b/components/subresource_filter/core/common/flat/indexed_ruleset.fbs new file mode 100644 index 0000000..9126228 --- /dev/null +++ b/components/subresource_filter/core/common/flat/indexed_ruleset.fbs
@@ -0,0 +1,22 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TODO(pkalinnikov): Make including by absolute path work. +include "url_pattern_index.fbs"; + +namespace subresource_filter.flat; + +// The top-level data structure used to store URL rules. +table IndexedRuleset { + // The index of all blacklist URL rules. + blacklist_index : UrlPatternIndex; + + // The index of all whitelist URL rules, except pure deactivation rules. + whitelist_index : UrlPatternIndex; + + // The index of all whitelist URL rules with activation options. + deactivation_index : UrlPatternIndex; +} + +root_type IndexedRuleset;
diff --git a/components/subresource_filter/core/common/flat/rules.fbs b/components/subresource_filter/core/common/flat/url_pattern_index.fbs similarity index 88% rename from components/subresource_filter/core/common/flat/rules.fbs rename to components/subresource_filter/core/common/flat/url_pattern_index.fbs index fdeaea9..ace4a05 100644 --- a/components/subresource_filter/core/common/flat/rules.fbs +++ b/components/subresource_filter/core/common/flat/url_pattern_index.fbs
@@ -1,3 +1,7 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + namespace subresource_filter.flat; // Corresponds to subresource_filter::proto::UrlPatternType. @@ -89,16 +93,4 @@ fallback_rules : [UrlRule]; } -// The top-level data structure used to store URL rules. -table IndexedRuleset { - // The index of all blacklist URL rules. - blacklist_index : UrlPatternIndex; - - // The index of all whitelist URL rules, except pure activation rules. - whitelist_index : UrlPatternIndex; - - // The index of all whitelist URL rules with activation options. - activation_index : UrlPatternIndex; -} - -root_type IndexedRuleset; +root_type UrlPatternIndex;
diff --git a/components/subresource_filter/core/common/indexed_ruleset.cc b/components/subresource_filter/core/common/indexed_ruleset.cc index 66d08f4..edbbee8 100644 --- a/components/subresource_filter/core/common/indexed_ruleset.cc +++ b/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -4,558 +4,56 @@ #include "components/subresource_filter/core/common/indexed_ruleset.h" -#include <algorithm> -#include <limits> -#include <string> - #include "base/logging.h" -#include "base/numerics/safe_conversions.h" -#include "base/strings/string_util.h" #include "components/subresource_filter/core/common/first_party_origin.h" -#include "components/subresource_filter/core/common/ngram_extractor.h" -#include "components/subresource_filter/core/common/url_pattern.h" -#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h" +#include "url/gurl.h" +#include "url/origin.h" namespace subresource_filter { -namespace { - -using FlatStringOffset = flatbuffers::Offset<flatbuffers::String>; -using FlatDomains = flatbuffers::Vector<FlatStringOffset>; -using FlatDomainsOffset = flatbuffers::Offset<FlatDomains>; - -base::StringPiece ToStringPiece(const flatbuffers::String* string) { - DCHECK(string); - return base::StringPiece(string->c_str(), string->size()); -} - -// Performs three-way comparison between two domains. In the total order defined -// by this predicate, the lengths of domains will be monotonically decreasing. -int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain) { - if (lhs_domain.size() != rhs_domain.size()) - return lhs_domain.size() > rhs_domain.size() ? -1 : 1; - return lhs_domain.compare(rhs_domain); -} - -bool HasNoUpperAscii(base::StringPiece string) { - return std::none_of(string.begin(), string.end(), - [](char c) { return base::IsAsciiUpper(c); }); -} - -// Checks whether a URL |rule| can be converted to its FlatBuffers equivalent, -// and performs the actual conversion. -class UrlRuleFlatBufferConverter { - public: - // Creates the converter, and initializes |is_convertible| bit. If - // |is_convertible| == true, then all the fields, needed for serializing the - // |rule| to FlatBuffer, are initialized (|options|, |anchor_right|, etc.). - UrlRuleFlatBufferConverter(const proto::UrlRule& rule) : rule_(rule) { - is_convertible_ = InitializeOptions() && InitializeElementTypes() && - InitializeActivationTypes() && InitializeUrlPattern() && - IsMeaningful(); - } - - // Returns whether the |rule| can be converted to its FlatBuffers equivalent. - // The conversion is not possible if the rule has attributes not supported by - // this client version. - bool is_convertible() const { return is_convertible_; } - - bool has_element_types() const { return !!element_types_; } - bool has_activation_types() const { return !!activation_types_; } - - // Writes the URL |rule| to the FlatBuffer using the |builder|, and returns - // the offset to the serialized rule. - flatbuffers::Offset<flat::UrlRule> SerializeConvertedRule( - flatbuffers::FlatBufferBuilder* builder) const { - DCHECK(is_convertible()); - - FlatDomainsOffset domains_included_offset; - FlatDomainsOffset domains_excluded_offset; - if (rule_.domains_size()) { - // TODO(pkalinnikov): Consider sharing the vectors between rules. - std::vector<FlatStringOffset> domains_included; - std::vector<FlatStringOffset> domains_excluded; - // Reserve only for |domains_included| because it is expected to be the - // one used more frequently. - domains_included.reserve(rule_.domains_size()); - - for (const auto& domain_list_item : rule_.domains()) { - // Note: The |domain| can have non-ASCII UTF-8 characters, but - // ToLowerASCII leaves these intact. - // TODO(pkalinnikov): Convert non-ASCII characters to lower case too. - // TODO(pkalinnikov): Possibly convert Punycode to IDN here or directly - // assume this is done in the proto::UrlRule. - const std::string& domain = domain_list_item.domain(); - auto offset = builder->CreateSharedString( - HasNoUpperAscii(domain) ? domain : base::ToLowerASCII(domain)); - - if (domain_list_item.exclude()) - domains_excluded.push_back(offset); - else - domains_included.push_back(offset); - } - - // The comparator ensuring the domains order necessary for fast matching. - auto precedes = [&builder](FlatStringOffset lhs, FlatStringOffset rhs) { - return CompareDomains(ToStringPiece(flatbuffers::GetTemporaryPointer( - *builder, lhs)), - ToStringPiece(flatbuffers::GetTemporaryPointer( - *builder, rhs))) < 0; - }; - - // The domains are stored in sorted order to support fast matching. - if (!domains_included.empty()) { - // TODO(pkalinnikov): Don't sort if it is already sorted offline. - std::sort(domains_included.begin(), domains_included.end(), precedes); - domains_included_offset = builder->CreateVector(domains_included); - } - if (!domains_excluded.empty()) { - std::sort(domains_excluded.begin(), domains_excluded.end(), precedes); - domains_excluded_offset = builder->CreateVector(domains_excluded); - } - } - - auto url_pattern_offset = builder->CreateString(rule_.url_pattern()); - - return flat::CreateUrlRule( - *builder, options_, element_types_, activation_types_, - url_pattern_type_, anchor_left_, anchor_right_, domains_included_offset, - domains_excluded_offset, url_pattern_offset); - } - - private: - static bool ConvertAnchorType(proto::AnchorType anchor_type, - flat::AnchorType* result) { - switch (anchor_type) { - case proto::ANCHOR_TYPE_NONE: - *result = flat::AnchorType_NONE; - break; - case proto::ANCHOR_TYPE_BOUNDARY: - *result = flat::AnchorType_BOUNDARY; - break; - case proto::ANCHOR_TYPE_SUBDOMAIN: - *result = flat::AnchorType_SUBDOMAIN; - break; - default: - return false; // Unsupported anchor type. - } - return true; - } - - bool InitializeOptions() { - if (rule_.semantics() == proto::RULE_SEMANTICS_WHITELIST) { - options_ |= flat::OptionFlag_IS_WHITELIST; - } else if (rule_.semantics() != proto::RULE_SEMANTICS_BLACKLIST) { - return false; // Unsupported semantics. - } - - switch (rule_.source_type()) { - case proto::SOURCE_TYPE_ANY: - options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY; - // Note: fall through here intentionally. - case proto::SOURCE_TYPE_FIRST_PARTY: - options_ |= flat::OptionFlag_APPLIES_TO_FIRST_PARTY; - break; - case proto::SOURCE_TYPE_THIRD_PARTY: - options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY; - break; - - default: - return false; // Unsupported source type. - } - - if (rule_.match_case()) - options_ |= flat::OptionFlag_IS_MATCH_CASE; - - return true; - } - - bool InitializeElementTypes() { - static_assert( - proto::ELEMENT_TYPE_ALL <= std::numeric_limits<uint16_t>::max(), - "Element types can not be stored in uint16_t."); - element_types_ = static_cast<uint16_t>(rule_.element_types()); - - // Note: Normally we can not distinguish between the main plugin resource - // and any other loads it makes. We treat them both as OBJECT requests. - if (element_types_ & proto::ELEMENT_TYPE_OBJECT_SUBREQUEST) - element_types_ |= proto::ELEMENT_TYPE_OBJECT; - - // Ignore unknown element types. - element_types_ &= proto::ELEMENT_TYPE_ALL; - // Filtering popups is not supported. - element_types_ &= ~proto::ELEMENT_TYPE_POPUP; - - return true; - } - - bool InitializeActivationTypes() { - static_assert( - proto::ACTIVATION_TYPE_ALL <= std::numeric_limits<uint8_t>::max(), - "Activation types can not be stored in uint8_t."); - activation_types_ = static_cast<uint8_t>(rule_.activation_types()); - - // Ignore unknown activation types. - activation_types_ &= proto::ACTIVATION_TYPE_ALL; - // No need in CSS activation, because the CSS rules are not supported. - activation_types_ &= - ~(proto::ACTIVATION_TYPE_ELEMHIDE | proto::ACTIVATION_TYPE_GENERICHIDE); - - return true; - } - - bool InitializeUrlPattern() { - switch (rule_.url_pattern_type()) { - case proto::URL_PATTERN_TYPE_SUBSTRING: - url_pattern_type_ = flat::UrlPatternType_SUBSTRING; - break; - case proto::URL_PATTERN_TYPE_WILDCARDED: - url_pattern_type_ = flat::UrlPatternType_WILDCARDED; - break; - - // TODO(pkalinnikov): Implement REGEXP rules matching. - case proto::URL_PATTERN_TYPE_REGEXP: - default: - return false; // Unsupported URL pattern type. - } - - if (!ConvertAnchorType(rule_.anchor_left(), &anchor_left_) || - !ConvertAnchorType(rule_.anchor_right(), &anchor_right_)) { - return false; - } - if (anchor_right_ == flat::AnchorType_SUBDOMAIN) - return false; // Unsupported right anchor. - - return true; - } - - // Returns whether the rule is not a no-op after all the modifications above. - bool IsMeaningful() const { return element_types_ || activation_types_; } - - const proto::UrlRule& rule_; - - uint8_t options_ = 0; - uint16_t element_types_ = 0; - uint8_t activation_types_ = 0; - flat::UrlPatternType url_pattern_type_ = flat::UrlPatternType_WILDCARDED; - flat::AnchorType anchor_left_ = flat::AnchorType_NONE; - flat::AnchorType anchor_right_ = flat::AnchorType_NONE; - - bool is_convertible_ = true; -}; - -} // namespace - // RulesetIndexer -------------------------------------------------------------- // static const int RulesetIndexer::kIndexedFormatVersion = 17; -RulesetIndexer::MutableUrlPatternIndex::MutableUrlPatternIndex() = default; -RulesetIndexer::MutableUrlPatternIndex::~MutableUrlPatternIndex() = default; +RulesetIndexer::RulesetIndexer() + : blacklist_(&builder_), whitelist_(&builder_), deactivation_(&builder_) {} -RulesetIndexer::RulesetIndexer() = default; RulesetIndexer::~RulesetIndexer() = default; bool RulesetIndexer::AddUrlRule(const proto::UrlRule& rule) { - UrlRuleFlatBufferConverter converter(rule); - if (!converter.is_convertible()) + const UrlRuleOffset offset = SerializeUrlRule(rule, &builder_); + // Note: A zero offset.o means a "nullptr" offset. It is returned when the + // rule has not been serialized. + if (!offset.o) return false; - DCHECK_NE(rule.url_pattern_type(), proto::URL_PATTERN_TYPE_REGEXP); - auto rule_offset = converter.SerializeConvertedRule(&builder_); - - auto add_rule_to_index = [&rule, rule_offset](MutableUrlPatternIndex* index) { - NGram ngram = - GetMostDistinctiveNGram(index->ngram_index, rule.url_pattern()); - if (ngram) { - index->ngram_index[ngram].push_back(rule_offset); - } else { - // TODO(pkalinnikov): Index fallback rules as well. - index->fallback_rules.push_back(rule_offset); - } - }; if (rule.semantics() == proto::RULE_SEMANTICS_BLACKLIST) { - add_rule_to_index(&blacklist_); + blacklist_.IndexUrlRule(offset); } else { - if (converter.has_element_types()) - add_rule_to_index(&whitelist_); - if (converter.has_activation_types()) - add_rule_to_index(&activation_); + const auto* flat_rule = flatbuffers::GetTemporaryPointer(builder_, offset); + DCHECK(flat_rule); + if (flat_rule->element_types()) + whitelist_.IndexUrlRule(offset); + if (flat_rule->activation_types()) + deactivation_.IndexUrlRule(offset); } return true; } void RulesetIndexer::Finish() { - auto blacklist_offset = SerializeUrlPatternIndex(blacklist_); - auto whitelist_offset = SerializeUrlPatternIndex(whitelist_); - auto activation_offset = SerializeUrlPatternIndex(activation_); + auto blacklist_offset = blacklist_.Finish(); + auto whitelist_offset = whitelist_.Finish(); + auto deactivation_offset = deactivation_.Finish(); auto url_rules_index_offset = flat::CreateIndexedRuleset( - builder_, blacklist_offset, whitelist_offset, activation_offset); + builder_, blacklist_offset, whitelist_offset, deactivation_offset); builder_.Finish(url_rules_index_offset); } -// static -NGram RulesetIndexer::GetMostDistinctiveNGram( - const MutableNGramIndex& ngram_index, - base::StringPiece pattern) { - size_t min_list_size = std::numeric_limits<size_t>::max(); - NGram best_ngram = 0; - - auto ngrams = CreateNGramExtractor<kNGramSize, NGram>( - pattern, [](char c) { return c == '*' || c == '^'; }); - - for (uint64_t ngram : ngrams) { - const MutableUrlRuleList* rules = ngram_index.Get(ngram); - const size_t list_size = rules ? rules->size() : 0; - if (list_size < min_list_size) { - // TODO(pkalinnikov): Pick random of the same-sized lists. - min_list_size = list_size; - best_ngram = ngram; - if (list_size == 0) - break; - } - } - - return best_ngram; -} - -flatbuffers::Offset<flat::UrlPatternIndex> -RulesetIndexer::SerializeUrlPatternIndex(const MutableUrlPatternIndex& index) { - const MutableNGramIndex& ngram_index = index.ngram_index; - - std::vector<flatbuffers::Offset<flat::NGramToRules>> flat_hash_table( - ngram_index.table_size()); - - flatbuffers::Offset<flat::NGramToRules> empty_slot_offset = - flat::CreateNGramToRules(builder_); - for (size_t i = 0, size = ngram_index.table_size(); i != size; ++i) { - const uint32_t entry_index = ngram_index.hash_table()[i]; - if (entry_index >= ngram_index.size()) { - flat_hash_table[i] = empty_slot_offset; - continue; - } - const MutableNGramIndex::EntryType& entry = - ngram_index.entries()[entry_index]; - auto rules_offset = builder_.CreateVector(entry.second); - flat_hash_table[i] = - flat::CreateNGramToRules(builder_, entry.first, rules_offset); - } - auto ngram_index_offset = builder_.CreateVector(flat_hash_table); - - auto fallback_rules_offset = builder_.CreateVector(index.fallback_rules); - - return flat::CreateUrlPatternIndex(builder_, kNGramSize, ngram_index_offset, - empty_slot_offset, fallback_rules_offset); -} - // IndexedRulesetMatcher ------------------------------------------------------- -namespace { - -using FlatUrlRuleList = flatbuffers::Vector<flatbuffers::Offset<flat::UrlRule>>; -using FlatNGramIndex = - flatbuffers::Vector<flatbuffers::Offset<flat::NGramToRules>>; - -// Returns the size of the longest (sub-)domain of |origin| matching one of the -// |domains| in the list. -// -// The |domains| should be sorted in descending order of their length, and -// ascending alphabetical order within the groups of same-length domains. -size_t GetLongestMatchingSubdomain(const url::Origin& origin, - const FlatDomains& domains) { - // If the |domains| list is short, then the simple strategy is usually faster. - if (domains.size() <= 5) { - for (auto* domain : domains) { - const base::StringPiece domain_piece = ToStringPiece(domain); - if (origin.DomainIs(domain_piece)) - return domain_piece.size(); - } - return 0; - } - // Otherwise look for each subdomain of the |origin| using binary search. - - DCHECK(!origin.unique()); - base::StringPiece canonicalized_host(origin.host()); - if (canonicalized_host.empty()) - return 0; - - // If the host name ends with a dot, then ignore it. - if (canonicalized_host.back() == '.') - canonicalized_host.remove_suffix(1); - - // The |left| bound of the search is shared between iterations, because - // subdomains are considered in decreasing order of their lengths, therefore - // each consecutive lower_bound will be at least as far as the previous. - flatbuffers::uoffset_t left = 0; - for (size_t position = 0;; ++position) { - const base::StringPiece subdomain = canonicalized_host.substr(position); - - flatbuffers::uoffset_t right = domains.size(); - while (left + 1 < right) { - auto middle = left + (right - left) / 2; - DCHECK_LT(middle, domains.size()); - if (CompareDomains(ToStringPiece(domains[middle]), subdomain) <= 0) - left = middle; - else - right = middle; - } - - DCHECK_LT(left, domains.size()); - if (ToStringPiece(domains[left]) == subdomain) - return subdomain.size(); - - position = canonicalized_host.find('.', position); - if (position == base::StringPiece::npos) - break; - } - - return 0; -} - -// Returns whether the |origin| matches the domain list of the |rule|. A match -// means that the longest domain in |domains| that |origin| is a sub-domain of -// is not an exception OR all the |domains| are exceptions and neither matches -// the |origin|. Thus, domain filters with more domain components trump filters -// with fewer domain components, i.e. the more specific a filter is, the higher -// the priority. -// -// A rule whose domain list is empty or contains only negative domains is still -// considered a "generic" rule. Therefore, if |disable_generic_rules| is set, -// this function will always return false for such rules. -bool DoesOriginMatchDomainList(const url::Origin& origin, - const flat::UrlRule& rule, - bool disable_generic_rules) { - const bool is_generic = !rule.domains_included(); - DCHECK(is_generic || rule.domains_included()->size()); - if (disable_generic_rules && is_generic) - return false; - - // Unique |origin| matches lists of exception domains only. - if (origin.unique()) - return is_generic; - - size_t longest_matching_included_domain_length = 1; - if (!is_generic) { - longest_matching_included_domain_length = - GetLongestMatchingSubdomain(origin, *rule.domains_included()); - } - if (longest_matching_included_domain_length && rule.domains_excluded()) { - return GetLongestMatchingSubdomain(origin, *rule.domains_excluded()) < - longest_matching_included_domain_length; - } - return !!longest_matching_included_domain_length; -} - -// Returns whether the request matches flags of the specified URL |rule|. Takes -// into account: -// - |element_type| of the requested resource, if not *_UNSPECIFIED. -// - |activation_type| for a subdocument request, if not *_UNSPECIFIED. -// - Whether the resource |is_third_party| w.r.t. its embedding document. -bool DoesRuleFlagsMatch(const flat::UrlRule& rule, - proto::ElementType element_type, - proto::ActivationType activation_type, - bool is_third_party) { - DCHECK(element_type == proto::ELEMENT_TYPE_UNSPECIFIED || - activation_type == proto::ACTIVATION_TYPE_UNSPECIFIED); - - if (element_type != proto::ELEMENT_TYPE_UNSPECIFIED && - !(rule.element_types() & element_type)) { - return false; - } - if (activation_type != proto::ACTIVATION_TYPE_UNSPECIFIED && - !(rule.activation_types() & activation_type)) { - return false; - } - - if (is_third_party && - !(rule.options() & flat::OptionFlag_APPLIES_TO_THIRD_PARTY)) { - return false; - } - if (!is_third_party && - !(rule.options() & flat::OptionFlag_APPLIES_TO_FIRST_PARTY)) { - return false; - } - - return true; -} - -bool MatchesAny(const FlatUrlRuleList* rules, - const GURL& url, - const url::Origin& document_origin, - proto::ElementType element_type, - proto::ActivationType activation_type, - bool is_third_party, - bool disable_generic_rules) { - if (!rules) - return false; - for (const flat::UrlRule* rule : *rules) { - DCHECK_NE(rule, nullptr); - DCHECK_NE(rule->url_pattern_type(), flat::UrlPatternType_REGEXP); - if (!DoesRuleFlagsMatch(*rule, element_type, activation_type, - is_third_party)) { - continue; - } - if (!UrlPattern(*rule).MatchesUrl(url)) - continue; - - if (DoesOriginMatchDomainList(document_origin, *rule, - disable_generic_rules)) { - return true; - } - } - - return false; -} - -// Returns whether the network request matches a particular part of the index. -// |is_third_party| should reflect the relation between |url| and -// |document_origin|. -bool IsMatch(const flat::UrlPatternIndex* index, - const GURL& url, - const url::Origin& document_origin, - proto::ElementType element_type, - proto::ActivationType activation_type, - bool is_third_party, - bool disable_generic_rules) { - if (!index) - return false; - const FlatNGramIndex* hash_table = index->ngram_index(); - const flat::NGramToRules* empty_slot = index->ngram_index_empty_slot(); - DCHECK_NE(hash_table, nullptr); - - NGramHashTableProber prober; - - auto ngrams = CreateNGramExtractor<kNGramSize, uint64_t>( - url.spec(), [](char) { return false; }); - for (uint64_t ngram : ngrams) { - const size_t slot_index = prober.FindSlot( - ngram, base::strict_cast<size_t>(hash_table->size()), - [hash_table, empty_slot](NGram ngram, size_t slot_index) { - const flat::NGramToRules* entry = hash_table->Get(slot_index); - DCHECK_NE(entry, nullptr); - return entry == empty_slot || entry->ngram() == ngram; - }); - DCHECK_LT(slot_index, hash_table->size()); - - const flat::NGramToRules* entry = hash_table->Get(slot_index); - if (entry == empty_slot) - continue; - if (MatchesAny(entry->rule_list(), url, document_origin, element_type, - activation_type, is_third_party, disable_generic_rules)) { - return true; - } - } - - const FlatUrlRuleList* rules = index->fallback_rules(); - return MatchesAny(rules, url, document_origin, element_type, activation_type, - is_third_party, disable_generic_rules); -} - -} // namespace - // static bool IndexedRulesetMatcher::Verify(const uint8_t* buffer, size_t size) { flatbuffers::Verifier verifier(buffer, size); @@ -563,24 +61,18 @@ } IndexedRulesetMatcher::IndexedRulesetMatcher(const uint8_t* buffer, size_t size) - : root_(flat::GetIndexedRuleset(buffer)) { - const flat::UrlPatternIndex* index = root_->blacklist_index(); - DCHECK(!index || index->n() == kNGramSize); - index = root_->whitelist_index(); - DCHECK(!index || index->n() == kNGramSize); -} + : root_(flat::GetIndexedRuleset(buffer)), + blacklist_(root_->blacklist_index()), + whitelist_(root_->whitelist_index()), + deactivation_(root_->deactivation_index()) {} bool IndexedRulesetMatcher::ShouldDisableFilteringForDocument( const GURL& document_url, const url::Origin& parent_document_origin, proto::ActivationType activation_type) const { - if (!document_url.is_valid() || - activation_type == proto::ACTIVATION_TYPE_UNSPECIFIED) { - return false; - } - return IsMatch( - root_->activation_index(), document_url, parent_document_origin, - proto::ELEMENT_TYPE_UNSPECIFIED, activation_type, + return !!deactivation_.FindMatch( + document_url, parent_document_origin, proto::ELEMENT_TYPE_UNSPECIFIED, + activation_type, FirstPartyOrigin::IsThirdParty(document_url, parent_document_origin), false); } @@ -590,15 +82,13 @@ const FirstPartyOrigin& first_party, proto::ElementType element_type, bool disable_generic_rules) const { - if (!url.is_valid() || element_type == proto::ELEMENT_TYPE_UNSPECIFIED) - return false; const bool is_third_party = first_party.IsThirdParty(url); - return IsMatch(root_->blacklist_index(), url, first_party.origin(), - element_type, proto::ACTIVATION_TYPE_UNSPECIFIED, - is_third_party, disable_generic_rules) && - !IsMatch(root_->whitelist_index(), url, first_party.origin(), - element_type, proto::ACTIVATION_TYPE_UNSPECIFIED, - is_third_party, disable_generic_rules); + return !!blacklist_.FindMatch(url, first_party.origin(), element_type, + proto::ACTIVATION_TYPE_UNSPECIFIED, + is_third_party, disable_generic_rules) && + !whitelist_.FindMatch(url, first_party.origin(), element_type, + proto::ACTIVATION_TYPE_UNSPECIFIED, + is_third_party, disable_generic_rules); } } // namespace subresource_filter
diff --git a/components/subresource_filter/core/common/indexed_ruleset.h b/components/subresource_filter/core/common/indexed_ruleset.h index e5206d7..00588f8a 100644 --- a/components/subresource_filter/core/common/indexed_ruleset.h +++ b/components/subresource_filter/core/common/indexed_ruleset.h
@@ -5,33 +5,28 @@ #ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_ #define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_ +#include <stddef.h> #include <stdint.h> -#include <vector> - #include "base/macros.h" #include "base/numerics/safe_conversions.h" -#include "base/strings/string_piece.h" -#include "components/subresource_filter/core/common/closed_hash_map.h" -#include "components/subresource_filter/core/common/flat/rules_generated.h" -#include "components/subresource_filter/core/common/proto/rules.pb.h" -#include "components/subresource_filter/core/common/uint64_hasher.h" -#include "url/gurl.h" -#include "url/origin.h" +#include "components/subresource_filter/core/common/flat/indexed_ruleset_generated.h" +#include "components/subresource_filter/core/common/url_pattern_index.h" +#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h" + +class GURL; + +namespace url { +class Origin; +} namespace subresource_filter { class FirstPartyOrigin; -// The integer type used to represent N-grams. -using NGram = uint64_t; -// The hasher used for hashing N-grams. -using NGramHasher = Uint64Hasher; -// The hash table probe sequence used both by the ruleset builder and matcher. -using NGramHashTableProber = DefaultProber<NGram, NGramHasher>; - -constexpr size_t kNGramSize = 5; -static_assert(kNGramSize <= sizeof(NGram), "NGram type is too narrow."); +namespace proto { +class UrlRule; +} // The class used to construct flat data structures representing the set of URL // filtering rules, as well as the index of those. Internally owns a @@ -66,45 +61,12 @@ size_t size() const { return base::strict_cast<size_t>(builder_.GetSize()); } private: - using MutableUrlRuleList = std::vector<flatbuffers::Offset<flat::UrlRule>>; - using MutableNGramIndex = - ClosedHashMap<NGram, MutableUrlRuleList, NGramHashTableProber>; - - // Encapsulates a subset of the rules, and an index built on the URL patterns - // in these rules. The ruleset is divided into parts according to metadata of - // the rules. Currently there are two parts: blacklist and whitelist. - struct MutableUrlPatternIndex { - // This index contains all non-REGEXP rules that have at least one - // acceptable N-gram. For a single rule the N-gram used as an index key is - // picked greedily (see GetMostDistinctiveNGram). - MutableNGramIndex ngram_index; - - // A fallback list that contains all the rules with no acceptable N-gram, - // and all the REGEXP rules. - MutableUrlRuleList fallback_rules; - - MutableUrlPatternIndex(); - ~MutableUrlPatternIndex(); - }; - - // Returns an N-gram of the |pattern| encoded into the NGram integer type. The - // N-gram is picked using a greedy heuristic, i.e. the one is chosen which - // corresponds to the shortest list of rules within the |index|. If there are - // no valid N-grams in the |pattern|, the return value is 0. - static NGram GetMostDistinctiveNGram(const MutableNGramIndex& index, - base::StringPiece pattern); - - // Serialized an |index| built over a part of the ruleset, and returns its - // offset in the FlatBuffer. - flatbuffers::Offset<flat::UrlPatternIndex> SerializeUrlPatternIndex( - const MutableUrlPatternIndex& index); - - MutableUrlPatternIndex blacklist_; - MutableUrlPatternIndex whitelist_; - MutableUrlPatternIndex activation_; - flatbuffers::FlatBufferBuilder builder_; + UrlPatternIndexBuilder blacklist_; + UrlPatternIndexBuilder whitelist_; + UrlPatternIndexBuilder deactivation_; + DISALLOW_COPY_AND_ASSIGN(RulesetIndexer); }; @@ -142,6 +104,10 @@ private: const flat::IndexedRuleset* root_; + UrlPatternIndexMatcher blacklist_; + UrlPatternIndexMatcher whitelist_; + UrlPatternIndexMatcher deactivation_; + DISALLOW_COPY_AND_ASSIGN(IndexedRulesetMatcher); };
diff --git a/components/subresource_filter/core/common/indexed_ruleset_unittest.cc b/components/subresource_filter/core/common/indexed_ruleset_unittest.cc index 998fd74..41778883 100644 --- a/components/subresource_filter/core/common/indexed_ruleset_unittest.cc +++ b/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
@@ -10,158 +10,78 @@ #include "base/logging.h" #include "base/macros.h" -#include "base/strings/string_util.h" +#include "base/strings/string_piece.h" #include "components/subresource_filter/core/common/first_party_origin.h" #include "components/subresource_filter/core/common/proto/rules.pb.h" #include "components/subresource_filter/core/common/url_pattern.h" +#include "components/subresource_filter/core/common/url_rule_test_support.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" +#include "url/origin.h" namespace subresource_filter { -namespace { +using namespace testing; -constexpr proto::AnchorType kAnchorNone = proto::ANCHOR_TYPE_NONE; -constexpr proto::AnchorType kBoundary = proto::ANCHOR_TYPE_BOUNDARY; -constexpr proto::AnchorType kSubdomain = proto::ANCHOR_TYPE_SUBDOMAIN; -constexpr proto::UrlPatternType kSubstring = proto::URL_PATTERN_TYPE_SUBSTRING; - -constexpr proto::SourceType kAnyParty = proto::SOURCE_TYPE_ANY; -constexpr proto::SourceType kFirstParty = proto::SOURCE_TYPE_FIRST_PARTY; -constexpr proto::SourceType kThirdParty = proto::SOURCE_TYPE_THIRD_PARTY; - -constexpr proto::ElementType kAllElementTypes = proto::ELEMENT_TYPE_ALL; -constexpr proto::ElementType kOther = proto::ELEMENT_TYPE_OTHER; -constexpr proto::ElementType kImage = proto::ELEMENT_TYPE_IMAGE; -constexpr proto::ElementType kFont = proto::ELEMENT_TYPE_FONT; -constexpr proto::ElementType kScript = proto::ELEMENT_TYPE_SCRIPT; -constexpr proto::ElementType kPopup = proto::ELEMENT_TYPE_POPUP; -constexpr proto::ElementType kWebSocket = proto::ELEMENT_TYPE_WEBSOCKET; - -constexpr proto::ActivationType kDocument = proto::ACTIVATION_TYPE_DOCUMENT; -constexpr proto::ActivationType kGenericBlock = - proto::ACTIVATION_TYPE_GENERICBLOCK; - -// Note: Returns unique origin on origin_string == nullptr. -url::Origin GetOrigin(const char* origin_string) { - return origin_string ? url::Origin(GURL(origin_string)) : url::Origin(); -} - -class UrlRuleBuilder { +class SubresourceFilterIndexedRulesetTest : public ::testing::Test { public: - explicit UrlRuleBuilder(const UrlPattern& url_pattern, - bool is_whitelist = false) - : UrlRuleBuilder(url_pattern, kAnyParty, is_whitelist) {} - - UrlRuleBuilder(const UrlPattern& url_pattern, - proto::SourceType source_type, - bool is_whitelist) { - rule_.set_semantics(is_whitelist ? proto::RULE_SEMANTICS_WHITELIST - : proto::RULE_SEMANTICS_BLACKLIST); - - rule_.set_source_type(source_type); - rule_.set_element_types(kAllElementTypes); - - rule_.set_url_pattern_type(url_pattern.type()); - rule_.set_anchor_left(url_pattern.anchor_left()); - rule_.set_anchor_right(url_pattern.anchor_right()); - rule_.set_match_case(url_pattern.match_case()); - rule_.set_url_pattern(url_pattern.url_pattern().as_string()); - } - - UrlRuleBuilder& AddDomain(std::string domain_pattern) { - DCHECK(!domain_pattern.empty()); - auto* domain = rule_.add_domains(); - if (domain_pattern[0] == '~') { - domain_pattern.erase(0, 1); - domain->set_exclude(true); - } - domain->set_domain(domain_pattern); - return *this; - } - - UrlRuleBuilder& AddDomains(const std::vector<std::string>& domains) { - for (const std::string domain : domains) - AddDomain(domain); - return *this; - } - - const proto::UrlRule& rule() const { return rule_; } - proto::UrlRule& rule() { return rule_; } - - private: - proto::UrlRule rule_; - - DISALLOW_COPY_AND_ASSIGN(UrlRuleBuilder); -}; - -} // namespace - -class SubresourceFilterIndexedRulesetTest : public testing::Test { - public: - SubresourceFilterIndexedRulesetTest() = default; + SubresourceFilterIndexedRulesetTest() { Reset(); } protected: - bool ShouldAllow(const char* url, - const char* document_origin = nullptr, + bool ShouldAllow(base::StringPiece url, + base::StringPiece document_origin = nullptr, proto::ElementType element_type = kOther, bool disable_generic_rules = false) const { - DCHECK_NE(matcher_.get(), nullptr); - url::Origin origin = GetOrigin(document_origin); - FirstPartyOrigin first_party(origin); - return !matcher_->ShouldDisallowResourceLoad( - GURL(url), first_party, element_type, disable_generic_rules); - } - - bool ShouldAllow(const char* url, - const char* document_origin, - bool disable_generic_rules) const { - return ShouldAllow(url, document_origin, kOther, disable_generic_rules); - } - - bool ShouldDeactivate(const char* document_url, - const char* parent_document_origin = nullptr, - proto::ActivationType activation_type = - proto::ACTIVATION_TYPE_UNSPECIFIED) const { DCHECK(matcher_); - url::Origin origin = GetOrigin(parent_document_origin); - return matcher_->ShouldDisableFilteringForDocument(GURL(document_url), - origin, activation_type); + return !matcher_->ShouldDisallowResourceLoad( + GURL(url), FirstPartyOrigin(GetOrigin(document_origin)), element_type, + disable_generic_rules); } - void AddUrlRule(const proto::UrlRule& rule) { - ASSERT_TRUE(indexer_.AddUrlRule(rule)) << "URL pattern: " - << rule.url_pattern(); + bool ShouldDeactivate( + base::StringPiece document_url, + base::StringPiece parent_document_origin = nullptr, + proto::ActivationType activation_type = kNoActivation) const { + DCHECK(matcher_); + return matcher_->ShouldDisableFilteringForDocument( + GURL(document_url), GetOrigin(parent_document_origin), activation_type); } - void AddSimpleRule(const UrlPattern& url_pattern, bool is_whitelist) { - AddUrlRule(UrlRuleBuilder(url_pattern, is_whitelist).rule()); + bool AddUrlRule(const proto::UrlRule& rule) { + return indexer_->AddUrlRule(rule); } - void AddBlacklistRule(const UrlPattern& url_pattern, - proto::SourceType source_type = kAnyParty) { - AddUrlRule(UrlRuleBuilder(url_pattern, source_type, false).rule()); + bool AddSimpleRule(base::StringPiece url_pattern) { + return AddUrlRule(MakeUrlRule(UrlPattern(url_pattern, kSubstring))); } - void AddWhitelistRuleWithActivationTypes(const UrlPattern& url_pattern, - int32_t activation_types) { - UrlRuleBuilder builder(url_pattern, kAnyParty, true); - builder.rule().set_element_types(proto::ELEMENT_TYPE_UNSPECIFIED); - builder.rule().set_activation_types(activation_types); - AddUrlRule(builder.rule()); + bool AddSimpleWhitelistRule(base::StringPiece url_pattern) { + auto rule = MakeUrlRule(UrlPattern(url_pattern, kSubstring)); + rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST); + return AddUrlRule(rule); + } + + bool AddSimpleWhitelistRule(base::StringPiece url_pattern, + int32_t activation_types) { + auto rule = MakeUrlRule(url_pattern); + rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST); + rule.clear_element_types(); + rule.set_activation_types(activation_types); + return AddUrlRule(rule); } void Finish() { - indexer_.Finish(); - matcher_.reset(new IndexedRulesetMatcher(indexer_.data(), indexer_.size())); + indexer_->Finish(); + matcher_.reset( + new IndexedRulesetMatcher(indexer_->data(), indexer_->size())); } void Reset() { matcher_.reset(nullptr); - indexer_.~RulesetIndexer(); - new (&indexer_) RulesetIndexer(); + indexer_.reset(new RulesetIndexer); } - RulesetIndexer indexer_; + std::unique_ptr<RulesetIndexer> indexer_; std::unique_ptr<IndexedRulesetMatcher> matcher_; private: @@ -175,138 +95,103 @@ bool expect_allowed; } kTestCases[] = { // SUBSTRING - {{"abcd", kSubstring}, "http://example.com/abcd", false}, - {{"abcd", kSubstring}, "http://example.com/dcab", true}, - {{"42", kSubstring}, "http://example.com/adcd/picture42.png", false}, + {{"abcd", kSubstring}, "http://ex.com/abcd", false}, + {{"abcd", kSubstring}, "http://ex.com/dcab", true}, + {{"42", kSubstring}, "http://ex.com/adcd/picture42.png", false}, {{"&test", kSubstring}, - "http://example.com/params?para1=false&test=true", + "http://ex.com/params?para1=false&test=true", false}, - {{"-test-42.", kSubstring}, "http://example.com/unit-test-42.1", false}, + {{"-test-42.", kSubstring}, "http://ex.com/unit-test-42.1", false}, {{"/abcdtest160x600.", kSubstring}, - "http://example.com/abcdtest160x600.png", + "http://ex.com/abcdtest160x600.png", false}, // WILDCARDED - {{"http://example.com/abcd/picture*.png"}, - "http://example.com/abcd/picture42.png", + {{"http://ex.com/abcd/picture*.png"}, + "http://ex.com/abcd/picture42.png", false}, - {{"example.com", kSubdomain, kAnchorNone}, "http://example.com", false}, - {{"example.com", kSubdomain, kAnchorNone}, - "http://test.example.com", - false}, - {{"example.com", kSubdomain, kAnchorNone}, - "https://test.example.com.com", - false}, - {{"example.com", kSubdomain, kAnchorNone}, - "https://test.rest.example.com", - false}, - {{"example.com", kSubdomain, kAnchorNone}, - "https://test_example.com", - true}, + {{"ex.com", kSubdomain, kAnchorNone}, "http://ex.com", false}, + {{"ex.com", kSubdomain, kAnchorNone}, "http://test.ex.com", false}, + {{"ex.com", kSubdomain, kAnchorNone}, "https://test.ex.com.com", false}, + {{"ex.com", kSubdomain, kAnchorNone}, "https://test.rest.ex.com", false}, + {{"ex.com", kSubdomain, kAnchorNone}, "https://test_ex.com", true}, - {{"http://example.com", kBoundary, kAnchorNone}, - "http://example.com/", + {{"http://ex.com", kBoundary, kAnchorNone}, "http://ex.com/", false}, + {{"http://ex.com", kBoundary, kAnchorNone}, "http://ex.com/42", false}, + {{"http://ex.com", kBoundary, kAnchorNone}, + "http://ex.com/42/http://ex.com/", false}, - {{"http://example.com", kBoundary, kAnchorNone}, - "http://example.com/42", + {{"http://ex.com", kBoundary, kAnchorNone}, + "http://ex.com/42/http://ex.info/", false}, - {{"http://example.com", kBoundary, kAnchorNone}, - "http://example.com/42/http://example.com/", - false}, - {{"http://example.com", kBoundary, kAnchorNone}, - "http://example.com/42/http://example.info/", - false}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.com", - false}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.com/42", + {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com", false}, + {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/42", true}, + {{"http://ex.com/", kBoundary, kBoundary}, + "http://ex.info/42/http://ex.com/", true}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.info/42/http://example.com/", + {{"http://ex.com/", kBoundary, kBoundary}, + "http://ex.info/42/http://ex.com/", true}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.info/42/http://example.com/", + {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/", false}, + {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/42.swf", true}, + {{"http://ex.com/", kBoundary, kBoundary}, + "http://ex.info/redirect/http://ex.com/", true}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.com/", - false}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.com/42.swf", - true}, - {{"http://example.com/", kBoundary, kBoundary}, - "http://example.info/redirect/http://example.com/", - true}, - {{"pdf", kAnchorNone, kBoundary}, "http://example.com/abcd.pdf", false}, - {{"pdf", kAnchorNone, kBoundary}, "http://example.com/pdfium", true}, - {{"http://example.com^"}, "http://example.com/", false}, - {{"http://example.com^"}, "http://example.com:8000/", false}, - {{"http://example.com^"}, "http://example.com.ru", true}, - {{"^example.com^"}, - "http://example.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82", + {{"pdf", kAnchorNone, kBoundary}, "http://ex.com/abcd.pdf", false}, + {{"pdf", kAnchorNone, kBoundary}, "http://ex.com/pdfium", true}, + {{"http://ex.com^"}, "http://ex.com/", false}, + {{"http://ex.com^"}, "http://ex.com:8000/", false}, + {{"http://ex.com^"}, "http://ex.com.ru", true}, + {{"^ex.com^"}, + "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82", false}, {{"^42.loss^"}, - "http://example.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82", + "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82", false}, - // FIXME(pkalinnikov): The '^' at the end should match end-of-string. + // TODO(pkalinnikov): The '^' at the end should match end-of-string. + // // {"^%D1%82%D0%B5%D1%81%D1%82^", - // "http://example.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82", + // "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82", // false}, - // {"/abcd/*/picture^", "http://example.com/abcd/42/picture", false}, + // {"/abcd/*/picture^", "http://ex.com/abcd/42/picture", false}, - {{"/abcd/*/picture^"}, - "http://example.com/abcd/42/loss/picture?param", + {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/loss/picture?param", false}, + {{"/abcd/*/picture^"}, "http://ex.com/abcd//picture/42", false}, + {{"/abcd/*/picture^"}, "http://ex.com/abcd/picture", true}, + {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/pictureraph", true}, + {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/picture.swf", true}, + {{"test.ex.com^", kSubdomain, kAnchorNone}, + "http://test.ex.com/42.swf", false}, - {{"/abcd/*/picture^"}, "http://example.com/abcd//picture/42", false}, - {{"/abcd/*/picture^"}, "http://example.com/abcd/picture", true}, - {{"/abcd/*/picture^"}, "http://example.com/abcd/42/pictureraph", true}, - {{"/abcd/*/picture^"}, "http://example.com/abcd/42/picture.swf", true}, - {{"test.example.com^", kSubdomain, kAnchorNone}, - "http://test.example.com/42.swf", + {{"test.ex.com^", kSubdomain, kAnchorNone}, + "http://server1.test.ex.com/42.swf", false}, - {{"test.example.com^", kSubdomain, kAnchorNone}, - "http://server1.test.example.com/42.swf", + {{"test.ex.com^", kSubdomain, kAnchorNone}, + "https://test.ex.com:8000/", false}, - {{"test.example.com^", kSubdomain, kAnchorNone}, - "https://test.example.com:8000/", - false}, - {{"test.example.com^", kSubdomain, kAnchorNone}, - "http://test.example.com.ua/42.swf", + {{"test.ex.com^", kSubdomain, kAnchorNone}, + "http://test.ex.com.ua/42.swf", true}, - {{"test.example.com^", kSubdomain, kAnchorNone}, - "http://example.com/redirect/http://test.example.com/", + {{"test.ex.com^", kSubdomain, kAnchorNone}, + "http://ex.com/redirect/http://test.ex.com/", true}, - {{"/abcd/*"}, "https://example.com/abcd/", false}, - {{"/abcd/*"}, "http://example.com/abcd/picture.jpeg", false}, - {{"/abcd/*"}, "https://example.com/abcd", true}, - {{"/abcd/*"}, "http://abcd.example.com", true}, - {{"*/abcd/"}, "https://example.com/abcd/", false}, - {{"*/abcd/"}, "http://example.com/abcd/picture.jpeg", false}, - {{"*/abcd/"}, "https://example.com/test-abcd/", true}, - {{"*/abcd/"}, "http://abcd.example.com", true}, - - // FIXME(pkalinnikov): Implement REGEXP matching. - // REGEXP - // {"/test|rest\\d+/", "http://example.com/test42", false}, - // {"/test|rest\\d+/", "http://example.com/test", false}, - // {"/test|rest\\d+/", "http://example.com/rest42", false}, - // {"/test|rest\\d+/", "http://example.com/rest", true}, - // {"/example\\.com/.*\\/[a-zA-Z0-9]{3}/", "http://example.com/abcd/42y", - // false}, - // {"/example\\.com/.*\\/[a-zA-Z0-9]{3}/", "http://example.com/abcd/%42y", - // true}, - // {"||example.com^*/test.htm", "http://example.com/unit/test.html", - // false}, - // {"||example.com^*/test.htm", "http://examole.com/test.htm", true}, + {{"/abcd/*"}, "https://ex.com/abcd/", false}, + {{"/abcd/*"}, "http://ex.com/abcd/picture.jpeg", false}, + {{"/abcd/*"}, "https://ex.com/abcd", true}, + {{"/abcd/*"}, "http://abcd.ex.com", true}, + {{"*/abcd/"}, "https://ex.com/abcd/", false}, + {{"*/abcd/"}, "http://ex.com/abcd/picture.jpeg", false}, + {{"*/abcd/"}, "https://ex.com/test-abcd/", true}, + {{"*/abcd/"}, "http://abcd.ex.com", true}, }; for (const auto& test_case : kTestCases) { - SCOPED_TRACE(testing::Message() << "Rule: " << test_case.url_pattern - << "; URL: " << test_case.url); + SCOPED_TRACE(::testing::Message() << "UrlPattern: " << test_case.url_pattern + << "; URL: " << test_case.url); - AddBlacklistRule(test_case.url_pattern); + ASSERT_TRUE(AddUrlRule(MakeUrlRule(test_case.url_pattern))); Finish(); EXPECT_EQ(test_case.expect_allowed, ShouldAllow(test_case.url)); @@ -323,47 +208,39 @@ const char* document_origin; bool expect_allowed; } kTestCases[] = { - {"example.com", kThirdParty, "http://example.com", "http://exmpl.org", + {"ex.com", kThirdParty, "http://ex.com", "http://exmpl.org", false}, + {"ex.com", kThirdParty, "http://ex.com", "http://ex.com", true}, + {"ex.com", kThirdParty, "http://ex.com/path?k=v", "http://exmpl.org", false}, - {"example.com", kThirdParty, "http://example.com", "http://example.com", + {"ex.com", kThirdParty, "http://ex.com/path?k=v", "http://ex.com", true}, + {"ex.com", kFirstParty, "http://ex.com/path?k=v", "http://ex.com", false}, + {"ex.com", kFirstParty, "http://ex.com/path?k=v", "http://exmpl.com", true}, - {"example.com", kThirdParty, "http://example.com/path?k=v", - "http://exmpl.org", false}, - {"example.com", kThirdParty, "http://example.com/path?k=v", - "http://example.com", true}, - {"example.com", kFirstParty, "http://example.com/path?k=v", - "http://example.com", false}, - {"example.com", kFirstParty, "http://example.com/path?k=v", - "http://exmpl.com", true}, - {"example.com", kAnyParty, "http://example.com/path?k=v", - "http://example.com", false}, - {"example.com", kAnyParty, "http://example.com/path?k=v", - "http://exmpl.com", false}, - {"example.com", kThirdParty, "http://subdomain.example.com", - "http://example.com", true}, - {"example.com", kThirdParty, "http://example.com", nullptr, false}, + {"ex.com", kAnyParty, "http://ex.com/path?k=v", "http://ex.com", false}, + {"ex.com", kAnyParty, "http://ex.com/path?k=v", "http://exmpl.com", + false}, + {"ex.com", kThirdParty, "http://subdomain.ex.com", "http://ex.com", true}, + {"ex.com", kThirdParty, "http://ex.com", nullptr, false}, // Public Suffix List tests. - {"example.com", kThirdParty, "http://two.example.com", - "http://one.example.com", true}, - {"example.com", kThirdParty, "http://example.com", - "http://one.example.com", true}, - {"example.com", kThirdParty, "http://two.example.com", - "http://example.com", true}, - {"example.com", kThirdParty, "http://example.com", "http://example.org", - false}, + {"ex.com", kThirdParty, "http://two.ex.com", "http://one.ex.com", true}, + {"ex.com", kThirdParty, "http://ex.com", "http://one.ex.com", true}, + {"ex.com", kThirdParty, "http://two.ex.com", "http://ex.com", true}, + {"ex.com", kThirdParty, "http://ex.com", "http://ex.org", false}, {"appspot.com", kThirdParty, "http://two.appspot.org", "http://one.appspot.com", true}, }; for (auto test_case : kTestCases) { - SCOPED_TRACE(testing::Message() - << "Rule: " << test_case.url_pattern << "; source: " - << (int)test_case.source_type << "; URL: " << test_case.url - << "; document: " << test_case.document_origin); + SCOPED_TRACE(::testing::Message() + << "UrlPattern: " << test_case.url_pattern + << "; SourceType: " << static_cast<int>(test_case.source_type) + << "; URL: " << test_case.url + << "; DocumentOrigin: " << test_case.document_origin); - AddBlacklistRule(UrlPattern(test_case.url_pattern, kSubstring), - test_case.source_type); + auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring)); + rule.set_source_type(test_case.source_type); + ASSERT_TRUE(AddUrlRule(rule)); Finish(); EXPECT_EQ(test_case.expect_allowed, @@ -378,7 +255,6 @@ const struct { std::vector<std::string> domains; const char* document_origin; - bool expect_allowed; } kTestCases[] = { {std::vector<std::string>(), nullptr, false}, @@ -469,13 +345,13 @@ }; for (const auto& test_case : kTestCases) { - SCOPED_TRACE(testing::Message() - << "Domains: " << base::JoinString(test_case.domains, "|") - << "; document: " << test_case.document_origin); + SCOPED_TRACE(::testing::Message() + << "Domains: " << ::testing::PrintToString(test_case.domains) + << "; DocumentOrigin: " << test_case.document_origin); - UrlRuleBuilder builder(UrlPattern(kUrl, kSubstring)); - builder.AddDomains(test_case.domains); - AddUrlRule(builder.rule()); + auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring)); + AddDomains(test_case.domains, &rule); + ASSERT_TRUE(AddUrlRule(rule)); Finish(); EXPECT_EQ(test_case.expect_allowed, @@ -503,26 +379,26 @@ domains.push_back("~sub.sub.c.sub." + domain); } - UrlRuleBuilder builder(UrlPattern(kUrl, kSubstring)); - builder.AddDomains(domains); - AddUrlRule(builder.rule()); + auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring)); + AddDomains(domains, &rule); + ASSERT_TRUE(AddUrlRule(rule)); Finish(); for (size_t i = 0; i < kDomains; ++i) { - SCOPED_TRACE(testing::Message() << "Iteration: " << i); + SCOPED_TRACE(::testing::Message() << "Iteration: " << i); const std::string domain = "domain" + std::to_string(i) + ".com"; - EXPECT_FALSE(ShouldAllow(kUrl, ("http://" + domain).c_str())); - EXPECT_TRUE(ShouldAllow(kUrl, ("http://sub." + domain).c_str())); - EXPECT_FALSE(ShouldAllow(kUrl, ("http://a.sub." + domain).c_str())); - EXPECT_FALSE(ShouldAllow(kUrl, ("http://b.sub." + domain).c_str())); - EXPECT_FALSE(ShouldAllow(kUrl, ("http://c.sub." + domain).c_str())); - EXPECT_TRUE(ShouldAllow(kUrl, ("http://aa.sub." + domain).c_str())); - EXPECT_TRUE(ShouldAllow(kUrl, ("http://ab.sub." + domain).c_str())); - EXPECT_TRUE(ShouldAllow(kUrl, ("http://ba.sub." + domain).c_str())); - EXPECT_TRUE(ShouldAllow(kUrl, ("http://bb.sub." + domain).c_str())); - EXPECT_FALSE(ShouldAllow(kUrl, ("http://sub.c.sub." + domain).c_str())); - EXPECT_TRUE(ShouldAllow(kUrl, ("http://sub.sub.c.sub." + domain).c_str())); + EXPECT_FALSE(ShouldAllow(kUrl, "http://" + domain)); + EXPECT_TRUE(ShouldAllow(kUrl, "http://sub." + domain)); + EXPECT_FALSE(ShouldAllow(kUrl, "http://a.sub." + domain)); + EXPECT_FALSE(ShouldAllow(kUrl, "http://b.sub." + domain)); + EXPECT_FALSE(ShouldAllow(kUrl, "http://c.sub." + domain)); + EXPECT_TRUE(ShouldAllow(kUrl, "http://aa.sub." + domain)); + EXPECT_TRUE(ShouldAllow(kUrl, "http://ab.sub." + domain)); + EXPECT_TRUE(ShouldAllow(kUrl, "http://ba.sub." + domain)); + EXPECT_TRUE(ShouldAllow(kUrl, "http://bb.sub." + domain)); + EXPECT_FALSE(ShouldAllow(kUrl, "http://sub.c.sub." + domain)); + EXPECT_TRUE(ShouldAllow(kUrl, "http://sub.sub.c.sub." + domain)); } } @@ -559,14 +435,16 @@ }; for (const auto& test_case : kTestCases) { - SCOPED_TRACE(testing::Message() - << "Rule: " << test_case.url_pattern << "; ElementTypes: " - << (int)test_case.element_types << "; URL: " << test_case.url - << "; ElementType: " << (int)test_case.element_type); + SCOPED_TRACE( + ::testing::Message() + << "UrlPattern: " << test_case.url_pattern + << "; ElementTypes: " << static_cast<int>(test_case.element_types) + << "; URL: " << test_case.url + << "; ElementType: " << static_cast<int>(test_case.element_type)); - UrlRuleBuilder builder(UrlPattern(test_case.url_pattern, kSubstring)); - builder.rule().set_element_types(test_case.element_types); - AddUrlRule(builder.rule()); + auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring)); + rule.set_element_types(test_case.element_types); + ASSERT_TRUE(AddUrlRule(rule)); Finish(); EXPECT_EQ(test_case.expect_allowed, @@ -600,15 +478,15 @@ }; for (const auto& test_case : kTestCases) { - SCOPED_TRACE(testing::Message() - << "Rule: " << test_case.url_pattern - << "; ActivationTypes: " << (int)test_case.activation_types - << "; DocURL: " << test_case.document_url - << "; ActivationType: " << (int)test_case.activation_type); + SCOPED_TRACE( + ::testing::Message() + << "UrlPattern: " << test_case.url_pattern + << "; ActivationTypes: " << static_cast<int>(test_case.activation_types) + << "; DocumentURL: " << test_case.document_url + << "; ActivationType: " << static_cast<int>(test_case.activation_type)); - AddWhitelistRuleWithActivationTypes( - UrlPattern(test_case.url_pattern, kSubstring), - test_case.activation_types); + ASSERT_TRUE(AddSimpleWhitelistRule(test_case.url_pattern, + test_case.activation_types)); Finish(); EXPECT_EQ(test_case.expect_disabled, @@ -626,11 +504,12 @@ } TEST_F(SubresourceFilterIndexedRulesetTest, RuleWithElementAndActivationTypes) { - UrlRuleBuilder builder(UrlPattern("allow.ex.com"), true /* is_whitelist */); - builder.rule().set_activation_types(kDocument); + auto rule = MakeUrlRule(UrlPattern("allow.ex.com", kSubstring)); + rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST); + rule.set_activation_types(kDocument); - AddUrlRule(builder.rule()); - AddBlacklistRule(UrlPattern("ex.com")); + ASSERT_TRUE(AddUrlRule(rule)); + ASSERT_TRUE(AddSimpleRule("ex.com")); Finish(); EXPECT_FALSE(ShouldAllow("http://ex.com")); @@ -643,37 +522,35 @@ } TEST_F(SubresourceFilterIndexedRulesetTest, MatchWithDisableGenericRules) { - // Generic rules. - ASSERT_NO_FATAL_FAILURE( - AddUrlRule(UrlRuleBuilder(UrlPattern("some_text", kSubstring)).rule())); - ASSERT_NO_FATAL_FAILURE( - AddUrlRule(UrlRuleBuilder(UrlPattern("another_text", kSubstring)) - .AddDomain("~example.com") - .rule())); + const struct { + const char* url_pattern; + std::vector<std::string> domains; + } kRules[] = { + // Generic rules. + {"some_text", std::vector<std::string>()}, + {"another_text", {"~example.com"}}, + {"final_text", {"~example1.com", "~example2.com"}}, + // Domain specific rules. + {"some_text", {"example1.com"}}, + {"more_text", {"example.com", "~exclude.example.com"}}, + {"last_text", {"example1.com", "sub.example2.com"}}, + }; - // Domain specific rules. - ASSERT_NO_FATAL_FAILURE( - AddUrlRule(UrlRuleBuilder(UrlPattern("some_text", kSubstring)) - .AddDomain("example1.com") - .rule())); - ASSERT_NO_FATAL_FAILURE( - AddUrlRule(UrlRuleBuilder(UrlPattern("more_text", kSubstring)) - .AddDomain("example.com") - .AddDomain("~exclude.example.com") - .rule())); - ASSERT_NO_FATAL_FAILURE( - AddUrlRule(UrlRuleBuilder(UrlPattern("last_text", kSubstring)) - .AddDomain("example1.com") - .AddDomain("sub.example2.com") - .rule())); + for (const auto& rule_data : kRules) { + auto rule = MakeUrlRule(UrlPattern(rule_data.url_pattern, kSubstring)); + AddDomains(rule_data.domains, &rule); + ASSERT_TRUE(AddUrlRule(rule)) + << "UrlPattern: " << rule_data.url_pattern + << "; Domains: " << ::testing::PrintToString(rule_data.domains); + } + // Note: Some of the rules have common domains (e.g., example1.com), which are // ultimately shared by FlatBuffers' CreateSharedString. The test also makes // sure that the data structure works properly with such optimization. - Finish(); const struct { - const char* url_pattern; + const char* url; const char* document_origin; bool should_allow_with_disable_generic_rules; bool should_allow_with_enable_all_rules; @@ -684,6 +561,10 @@ {"http://ex.com/another_text", "http://example.com", true, true}, {"http://ex.com/another_text", "http://example1.com", true, false}, + {"http://ex.com/final_text", "http://example.com", true, false}, + {"http://ex.com/final_text", "http://example1.com", true, true}, + {"http://ex.com/final_text", "http://example2.com", true, true}, + {"http://ex.com/more_text", "http://example.com", false, false}, {"http://ex.com/more_text", "http://exclude.example.com", true, true}, {"http://ex.com/more_text", "http://example1.com", true, true}, @@ -697,37 +578,37 @@ constexpr bool kDisableGenericRules = true; constexpr bool kEnableAllRules = false; for (const auto& test_case : kTestCases) { - SCOPED_TRACE(testing::Message() - << "Url: " << test_case.url_pattern - << "; document: " << test_case.document_origin); + SCOPED_TRACE(::testing::Message() + << "URL: " << test_case.url + << "; DocumentOrigin: " << test_case.document_origin); EXPECT_EQ(test_case.should_allow_with_disable_generic_rules, - ShouldAllow(test_case.url_pattern, test_case.document_origin, + ShouldAllow(test_case.url, test_case.document_origin, kOther, kDisableGenericRules)); EXPECT_EQ(test_case.should_allow_with_enable_all_rules, - ShouldAllow(test_case.url_pattern, test_case.document_origin, + ShouldAllow(test_case.url, test_case.document_origin, kOther, kEnableAllRules)); } } TEST_F(SubresourceFilterIndexedRulesetTest, EmptyRuleset) { Finish(); + EXPECT_TRUE(ShouldAllow(nullptr)); EXPECT_TRUE(ShouldAllow("http://example.com")); EXPECT_TRUE(ShouldAllow("http://another.example.com?param=val")); - EXPECT_TRUE(ShouldAllow(nullptr)); } TEST_F(SubresourceFilterIndexedRulesetTest, NoRuleApplies) { - AddSimpleRule(UrlPattern("?filtered_content=", kSubstring), false); - AddSimpleRule(UrlPattern("&filtered_content=", kSubstring), false); + ASSERT_TRUE(AddSimpleRule("?filter_out=")); + ASSERT_TRUE(AddSimpleRule("&filter_out=")); Finish(); EXPECT_TRUE(ShouldAllow("http://example.com")); - EXPECT_TRUE(ShouldAllow("http://example.com?filtered_not")); + EXPECT_TRUE(ShouldAllow("http://example.com?filter_not")); } TEST_F(SubresourceFilterIndexedRulesetTest, SimpleBlacklist) { - AddSimpleRule(UrlPattern("?param=", kSubstring), false); + ASSERT_TRUE(AddSimpleRule("?param=")); Finish(); EXPECT_TRUE(ShouldAllow("https://example.com")); @@ -735,26 +616,25 @@ } TEST_F(SubresourceFilterIndexedRulesetTest, SimpleWhitelist) { - AddSimpleRule(UrlPattern("example.com/?filtered_content=", kSubstring), true); + ASSERT_TRUE(AddSimpleWhitelistRule("example.com/?filter_out=")); Finish(); - EXPECT_TRUE(ShouldAllow("https://example.com?filtered_content=image1")); + EXPECT_TRUE(ShouldAllow("https://example.com?filter_out=true")); } -TEST_F(SubresourceFilterIndexedRulesetTest, BlacklistWhitelist) { - AddSimpleRule(UrlPattern("?filter=", kSubstring), false); - AddSimpleRule(UrlPattern("whitelisted.com/?filter=", kSubstring), true); +TEST_F(SubresourceFilterIndexedRulesetTest, SimpleBlacklistAndWhitelist) { + ASSERT_TRUE(AddSimpleRule("?filter=")); + ASSERT_TRUE(AddSimpleWhitelistRule("whitelisted.com/?filter=")); Finish(); - EXPECT_TRUE(ShouldAllow("https://whitelisted.com?filter=off")); - EXPECT_TRUE(ShouldAllow("https://notblacklisted.com")); EXPECT_FALSE(ShouldAllow("http://blacklisted.com?filter=on")); + EXPECT_TRUE(ShouldAllow("https://whitelisted.com?filter=on")); + EXPECT_TRUE(ShouldAllow("https://notblacklisted.com")); } TEST_F(SubresourceFilterIndexedRulesetTest, BlacklistAndActivationType) { - AddSimpleRule(UrlPattern("example.com", kSubstring), false); - AddWhitelistRuleWithActivationTypes(UrlPattern("example.com", kSubstring), - kDocument); + ASSERT_TRUE(AddSimpleRule("example.com")); + ASSERT_TRUE(AddSimpleWhitelistRule("example.com", kDocument)); Finish(); EXPECT_TRUE(ShouldDeactivate("https://example.com", nullptr, kDocument)); @@ -763,7 +643,7 @@ EXPECT_TRUE(ShouldAllow("https://xample.com")); } -TEST_F(SubresourceFilterIndexedRulesetTest, RuleWithUnsupportedTypes) { +TEST_F(SubresourceFilterIndexedRulesetTest, RulesWithUnsupportedTypes) { const struct { int element_types; int activation_types; @@ -779,21 +659,24 @@ {proto::ELEMENT_TYPE_POPUP, proto::ACTIVATION_TYPE_ELEMHIDE}, }; - for (const auto& rule : kRules) { - UrlRuleBuilder builder(UrlPattern("example.com")); - builder.rule().set_element_types(rule.element_types); - builder.rule().set_activation_types(rule.activation_types); - EXPECT_FALSE(indexer_.AddUrlRule(builder.rule())); + for (const auto& rule_data : kRules) { + auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring)); + rule.set_element_types(rule_data.element_types); + rule.set_activation_types(rule_data.activation_types); + EXPECT_FALSE(AddUrlRule(rule)) + << "ElementTypes: " << static_cast<int>(rule_data.element_types) + << "; ActivationTypes: " + << static_cast<int>(rule_data.activation_types); } - AddSimpleRule(UrlPattern("exmpl.com", kSubstring), false); - + ASSERT_TRUE(AddSimpleRule("exmpl.com")); Finish(); + EXPECT_TRUE(ShouldAllow("http://example.com/")); EXPECT_FALSE(ShouldAllow("https://exmpl.com/")); } TEST_F(SubresourceFilterIndexedRulesetTest, - RuleWithSupportedAndUnsupportedTypes) { + RulesWithSupportedAndUnsupportedTypes) { const struct { int element_types; int activation_types; @@ -803,18 +686,22 @@ {0, kDocument | (proto::ACTIVATION_TYPE_MAX << 1)}, }; - for (const auto& rule : kRules) { - UrlRuleBuilder builder(UrlPattern("example.com")); - builder.rule().set_element_types(rule.element_types); - builder.rule().set_activation_types(rule.activation_types); - if (rule.activation_types) - builder.rule().set_semantics(proto::RULE_SEMANTICS_WHITELIST); - EXPECT_TRUE(indexer_.AddUrlRule(builder.rule())); + for (const auto& rule_data : kRules) { + auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring)); + rule.set_element_types(rule_data.element_types); + rule.set_activation_types(rule_data.activation_types); + if (rule_data.activation_types) + rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST); + EXPECT_TRUE(AddUrlRule(rule)) + << "ElementTypes: " << static_cast<int>(rule_data.element_types) + << "; ActivationTypes: " + << static_cast<int>(rule_data.activation_types); } Finish(); EXPECT_FALSE(ShouldAllow("http://example.com/", nullptr, kImage)); EXPECT_FALSE(ShouldAllow("http://example.com/", nullptr, kScript)); + EXPECT_TRUE(ShouldAllow("http://example.com/", nullptr, kPopup)); EXPECT_TRUE(ShouldAllow("http://example.com/")); EXPECT_TRUE(ShouldDeactivate("http://example.com", nullptr, kDocument));
diff --git a/components/subresource_filter/core/common/url_pattern.cc b/components/subresource_filter/core/common/url_pattern.cc index d601f41..381def4b 100644 --- a/components/subresource_filter/core/common/url_pattern.cc +++ b/components/subresource_filter/core/common/url_pattern.cc
@@ -20,7 +20,7 @@ #include <ostream> #include "base/logging.h" -#include "components/subresource_filter/core/common/flat/rules_generated.h" +#include "components/subresource_filter/core/common/flat/url_pattern_index_generated.h" #include "components/subresource_filter/core/common/fuzzy_pattern_matching.h" #include "components/subresource_filter/core/common/string_splitter.h" #include "url/gurl.h"
diff --git a/components/subresource_filter/core/common/url_pattern_index.cc b/components/subresource_filter/core/common/url_pattern_index.cc new file mode 100644 index 0000000..49c3cb9 --- /dev/null +++ b/components/subresource_filter/core/common/url_pattern_index.cc
@@ -0,0 +1,566 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/subresource_filter/core/common/url_pattern_index.h" + +#include <algorithm> +#include <limits> +#include <string> + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "base/strings/string_util.h" +#include "components/subresource_filter/core/common/ngram_extractor.h" +#include "components/subresource_filter/core/common/url_pattern.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace subresource_filter { + +namespace { + +using FlatStringOffset = flatbuffers::Offset<flatbuffers::String>; +using FlatDomains = flatbuffers::Vector<FlatStringOffset>; +using FlatDomainsOffset = flatbuffers::Offset<FlatDomains>; + +base::StringPiece ToStringPiece(const flatbuffers::String* string) { + DCHECK(string); + return base::StringPiece(string->c_str(), string->size()); +} + +// Performs three-way comparison between two domains. In the total order defined +// by this predicate, the lengths of domains will be monotonically decreasing. +int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain) { + if (lhs_domain.size() != rhs_domain.size()) + return lhs_domain.size() > rhs_domain.size() ? -1 : 1; + return lhs_domain.compare(rhs_domain); +} + +bool HasNoUpperAscii(base::StringPiece string) { + return std::none_of(string.begin(), string.end(), + [](char c) { return base::IsAsciiUpper(c); }); +} + +// Checks whether a URL |rule| can be converted to its FlatBuffers equivalent, +// and performs the actual conversion. +class UrlRuleFlatBufferConverter { + public: + // Creates the converter, and initializes |is_convertible| bit. If + // |is_convertible| == true, then all the fields, needed for serializing the + // |rule| to FlatBuffer, are initialized (|options|, |anchor_right|, etc.). + explicit UrlRuleFlatBufferConverter(const proto::UrlRule& rule) + : rule_(rule) { + is_convertible_ = InitializeOptions() && InitializeElementTypes() && + InitializeActivationTypes() && InitializeUrlPattern() && + IsMeaningful(); + } + + // Returns whether the |rule| can be converted to its FlatBuffers equivalent. + // The conversion is not possible if the rule has attributes not supported by + // this client version. + bool is_convertible() const { return is_convertible_; } + + // Writes the URL |rule| to the FlatBuffer using the |builder|, and returns + // the offset to the serialized rule. + UrlRuleOffset SerializeConvertedRule( + flatbuffers::FlatBufferBuilder* builder) const { + DCHECK(is_convertible()); + + FlatDomainsOffset domains_included_offset; + FlatDomainsOffset domains_excluded_offset; + if (rule_.domains_size()) { + // TODO(pkalinnikov): Consider sharing the vectors between rules. + std::vector<FlatStringOffset> domains_included; + std::vector<FlatStringOffset> domains_excluded; + // Reserve only for |domains_included| because it is expected to be the + // one used more frequently. + domains_included.reserve(rule_.domains_size()); + + for (const auto& domain_list_item : rule_.domains()) { + // Note: The |domain| can have non-ASCII UTF-8 characters, but + // ToLowerASCII leaves these intact. + // TODO(pkalinnikov): Convert non-ASCII characters to lower case too. + // TODO(pkalinnikov): Possibly convert Punycode to IDN here or directly + // assume this is done in the proto::UrlRule. + const std::string& domain = domain_list_item.domain(); + auto offset = builder->CreateSharedString( + HasNoUpperAscii(domain) ? domain : base::ToLowerASCII(domain)); + + if (domain_list_item.exclude()) + domains_excluded.push_back(offset); + else + domains_included.push_back(offset); + } + + // The comparator ensuring the domains order necessary for fast matching. + auto precedes = [&builder](FlatStringOffset lhs, FlatStringOffset rhs) { + return CompareDomains(ToStringPiece(flatbuffers::GetTemporaryPointer( + *builder, lhs)), + ToStringPiece(flatbuffers::GetTemporaryPointer( + *builder, rhs))) < 0; + }; + + // The domains are stored in sorted order to support fast matching. + if (!domains_included.empty()) { + // TODO(pkalinnikov): Don't sort if it is already sorted offline. + std::sort(domains_included.begin(), domains_included.end(), precedes); + domains_included_offset = builder->CreateVector(domains_included); + } + if (!domains_excluded.empty()) { + std::sort(domains_excluded.begin(), domains_excluded.end(), precedes); + domains_excluded_offset = builder->CreateVector(domains_excluded); + } + } + + auto url_pattern_offset = builder->CreateString(rule_.url_pattern()); + + return flat::CreateUrlRule( + *builder, options_, element_types_, activation_types_, + url_pattern_type_, anchor_left_, anchor_right_, domains_included_offset, + domains_excluded_offset, url_pattern_offset); + } + + private: + static bool ConvertAnchorType(proto::AnchorType anchor_type, + flat::AnchorType* result) { + switch (anchor_type) { + case proto::ANCHOR_TYPE_NONE: + *result = flat::AnchorType_NONE; + break; + case proto::ANCHOR_TYPE_BOUNDARY: + *result = flat::AnchorType_BOUNDARY; + break; + case proto::ANCHOR_TYPE_SUBDOMAIN: + *result = flat::AnchorType_SUBDOMAIN; + break; + default: + return false; // Unsupported anchor type. + } + return true; + } + + bool InitializeOptions() { + if (rule_.semantics() == proto::RULE_SEMANTICS_WHITELIST) { + options_ |= flat::OptionFlag_IS_WHITELIST; + } else if (rule_.semantics() != proto::RULE_SEMANTICS_BLACKLIST) { + return false; // Unsupported semantics. + } + + switch (rule_.source_type()) { + case proto::SOURCE_TYPE_ANY: + options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY; + // Note: fall through here intentionally. + case proto::SOURCE_TYPE_FIRST_PARTY: + options_ |= flat::OptionFlag_APPLIES_TO_FIRST_PARTY; + break; + case proto::SOURCE_TYPE_THIRD_PARTY: + options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY; + break; + + default: + return false; // Unsupported source type. + } + + if (rule_.match_case()) + options_ |= flat::OptionFlag_IS_MATCH_CASE; + + return true; + } + + bool InitializeElementTypes() { + static_assert( + proto::ELEMENT_TYPE_ALL <= std::numeric_limits<uint16_t>::max(), + "Element types can not be stored in uint16_t."); + element_types_ = static_cast<uint16_t>(rule_.element_types()); + + // Note: Normally we can not distinguish between the main plugin resource + // and any other loads it makes. We treat them both as OBJECT requests. + if (element_types_ & proto::ELEMENT_TYPE_OBJECT_SUBREQUEST) + element_types_ |= proto::ELEMENT_TYPE_OBJECT; + + // Ignore unknown element types. + element_types_ &= proto::ELEMENT_TYPE_ALL; + // Filtering popups is not supported. + element_types_ &= ~proto::ELEMENT_TYPE_POPUP; + + return true; + } + + bool InitializeActivationTypes() { + static_assert( + proto::ACTIVATION_TYPE_ALL <= std::numeric_limits<uint8_t>::max(), + "Activation types can not be stored in uint8_t."); + activation_types_ = static_cast<uint8_t>(rule_.activation_types()); + + // Only the following activation types are supported, ignore the others. + activation_types_ &= + proto::ACTIVATION_TYPE_DOCUMENT | proto::ACTIVATION_TYPE_GENERICBLOCK; + + return true; + } + + bool InitializeUrlPattern() { + switch (rule_.url_pattern_type()) { + case proto::URL_PATTERN_TYPE_SUBSTRING: + url_pattern_type_ = flat::UrlPatternType_SUBSTRING; + break; + case proto::URL_PATTERN_TYPE_WILDCARDED: + url_pattern_type_ = flat::UrlPatternType_WILDCARDED; + break; + + // TODO(pkalinnikov): Implement REGEXP rules matching. + case proto::URL_PATTERN_TYPE_REGEXP: + default: + return false; // Unsupported URL pattern type. + } + + if (!ConvertAnchorType(rule_.anchor_left(), &anchor_left_) || + !ConvertAnchorType(rule_.anchor_right(), &anchor_right_)) { + return false; + } + if (anchor_right_ == flat::AnchorType_SUBDOMAIN) + return false; // Unsupported right anchor. + + return true; + } + + // Returns whether the rule is not a no-op after all the modifications above. + bool IsMeaningful() const { return element_types_ || activation_types_; } + + const proto::UrlRule& rule_; + + uint8_t options_ = 0; + uint16_t element_types_ = 0; + uint8_t activation_types_ = 0; + flat::UrlPatternType url_pattern_type_ = flat::UrlPatternType_WILDCARDED; + flat::AnchorType anchor_left_ = flat::AnchorType_NONE; + flat::AnchorType anchor_right_ = flat::AnchorType_NONE; + + bool is_convertible_ = true; +}; + +} // namespace + +// Helpers. -------------------------------------------------------------------- + +UrlRuleOffset SerializeUrlRule(const proto::UrlRule& rule, + flatbuffers::FlatBufferBuilder* builder) { + DCHECK(builder); + UrlRuleFlatBufferConverter converter(rule); + if (!converter.is_convertible()) + return UrlRuleOffset(); + DCHECK_NE(rule.url_pattern_type(), proto::URL_PATTERN_TYPE_REGEXP); + return converter.SerializeConvertedRule(builder); +} + +// UrlPatternIndexBuilder ------------------------------------------------------ + +UrlPatternIndexBuilder::UrlPatternIndexBuilder( + flatbuffers::FlatBufferBuilder* flat_builder) + : flat_builder_(flat_builder) { + DCHECK(flat_builder_); +} + +UrlPatternIndexBuilder::~UrlPatternIndexBuilder() = default; + +void UrlPatternIndexBuilder::IndexUrlRule(UrlRuleOffset offset) { + DCHECK(offset.o); + + const auto* rule = flatbuffers::GetTemporaryPointer(*flat_builder_, offset); + DCHECK(rule); + NGram ngram = GetMostDistinctiveNGram(ToStringPiece(rule->url_pattern())); + + if (ngram) { + ngram_index_[ngram].push_back(offset); + } else { + // TODO(pkalinnikov): Index fallback rules as well. + fallback_rules_.push_back(offset); + } +} + +UrlPatternIndexOffset UrlPatternIndexBuilder::Finish() { + std::vector<flatbuffers::Offset<flat::NGramToRules>> flat_hash_table( + ngram_index_.table_size()); + + flatbuffers::Offset<flat::NGramToRules> empty_slot_offset = + flat::CreateNGramToRules(*flat_builder_); + for (size_t i = 0, size = ngram_index_.table_size(); i != size; ++i) { + const uint32_t entry_index = ngram_index_.hash_table()[i]; + if (entry_index >= ngram_index_.size()) { + flat_hash_table[i] = empty_slot_offset; + continue; + } + const MutableNGramIndex::EntryType& entry = + ngram_index_.entries()[entry_index]; + auto rules_offset = flat_builder_->CreateVector(entry.second); + flat_hash_table[i] = + flat::CreateNGramToRules(*flat_builder_, entry.first, rules_offset); + } + auto ngram_index_offset = flat_builder_->CreateVector(flat_hash_table); + + auto fallback_rules_offset = flat_builder_->CreateVector(fallback_rules_); + + return flat::CreateUrlPatternIndex(*flat_builder_, kNGramSize, + ngram_index_offset, empty_slot_offset, + fallback_rules_offset); +} + +NGram UrlPatternIndexBuilder::GetMostDistinctiveNGram( + base::StringPiece pattern) { + size_t min_list_size = std::numeric_limits<size_t>::max(); + NGram best_ngram = 0; + + auto ngrams = CreateNGramExtractor<kNGramSize, NGram>( + pattern, [](char c) { return c == '*' || c == '^'; }); + + for (uint64_t ngram : ngrams) { + const MutableUrlRuleList* rules = ngram_index_.Get(ngram); + const size_t list_size = rules ? rules->size() : 0; + if (list_size < min_list_size) { + // TODO(pkalinnikov): Pick random of the same-sized lists. + min_list_size = list_size; + best_ngram = ngram; + if (list_size == 0) + break; + } + } + + return best_ngram; +} + +// UrlPatternIndex ------------------------------------------------------------- + +namespace { + +using FlatUrlRuleList = flatbuffers::Vector<flatbuffers::Offset<flat::UrlRule>>; +using FlatNGramIndex = + flatbuffers::Vector<flatbuffers::Offset<flat::NGramToRules>>; + +// Returns the size of the longest (sub-)domain of |origin| matching one of the +// |domains| in the list. +// +// The |domains| should be sorted in descending order of their length, and +// ascending alphabetical order within the groups of same-length domains. +size_t GetLongestMatchingSubdomain(const url::Origin& origin, + const FlatDomains& domains) { + // If the |domains| list is short, then the simple strategy is usually faster. + if (domains.size() <= 5) { + for (auto* domain : domains) { + const base::StringPiece domain_piece = ToStringPiece(domain); + if (origin.DomainIs(domain_piece)) + return domain_piece.size(); + } + return 0; + } + // Otherwise look for each subdomain of the |origin| using binary search. + + DCHECK(!origin.unique()); + base::StringPiece canonicalized_host(origin.host()); + if (canonicalized_host.empty()) + return 0; + + // If the host name ends with a dot, then ignore it. + if (canonicalized_host.back() == '.') + canonicalized_host.remove_suffix(1); + + // The |left| bound of the search is shared between iterations, because + // subdomains are considered in decreasing order of their lengths, therefore + // each consecutive lower_bound will be at least as far as the previous. + flatbuffers::uoffset_t left = 0; + for (size_t position = 0;; ++position) { + const base::StringPiece subdomain = canonicalized_host.substr(position); + + flatbuffers::uoffset_t right = domains.size(); + while (left + 1 < right) { + auto middle = left + (right - left) / 2; + DCHECK_LT(middle, domains.size()); + if (CompareDomains(ToStringPiece(domains[middle]), subdomain) <= 0) + left = middle; + else + right = middle; + } + + DCHECK_LT(left, domains.size()); + if (ToStringPiece(domains[left]) == subdomain) + return subdomain.size(); + + position = canonicalized_host.find('.', position); + if (position == base::StringPiece::npos) + break; + } + + return 0; +} + +// Returns whether the |origin| matches the domain list of the |rule|. A match +// means that the longest domain in |domains| that |origin| is a sub-domain of +// is not an exception OR all the |domains| are exceptions and neither matches +// the |origin|. Thus, domain filters with more domain components trump filters +// with fewer domain components, i.e. the more specific a filter is, the higher +// the priority. +// +// A rule whose domain list is empty or contains only negative domains is still +// considered a "generic" rule. Therefore, if |disable_generic_rules| is set, +// this function will always return false for such rules. +bool DoesOriginMatchDomainList(const url::Origin& origin, + const flat::UrlRule& rule, + bool disable_generic_rules) { + const bool is_generic = !rule.domains_included(); + DCHECK(is_generic || rule.domains_included()->size()); + if (disable_generic_rules && is_generic) + return false; + + // Unique |origin| matches lists of exception domains only. + if (origin.unique()) + return is_generic; + + size_t longest_matching_included_domain_length = 1; + if (!is_generic) { + longest_matching_included_domain_length = + GetLongestMatchingSubdomain(origin, *rule.domains_included()); + } + if (longest_matching_included_domain_length && rule.domains_excluded()) { + return GetLongestMatchingSubdomain(origin, *rule.domains_excluded()) < + longest_matching_included_domain_length; + } + return !!longest_matching_included_domain_length; +} + +// Returns whether the request matches flags of the specified URL |rule|. Takes +// into account: +// - |element_type| of the requested resource, if not *_UNSPECIFIED. +// - |activation_type| for a subdocument request, if not *_UNSPECIFIED. +// - Whether the resource |is_third_party| w.r.t. its embedding document. +bool DoesRuleFlagsMatch(const flat::UrlRule& rule, + proto::ElementType element_type, + proto::ActivationType activation_type, + bool is_third_party) { + DCHECK((element_type == proto::ELEMENT_TYPE_UNSPECIFIED) != + (activation_type == proto::ACTIVATION_TYPE_UNSPECIFIED)); + + if (element_type != proto::ELEMENT_TYPE_UNSPECIFIED && + !(rule.element_types() & element_type)) { + return false; + } + if (activation_type != proto::ACTIVATION_TYPE_UNSPECIFIED && + !(rule.activation_types() & activation_type)) { + return false; + } + + if (is_third_party && + !(rule.options() & flat::OptionFlag_APPLIES_TO_THIRD_PARTY)) { + return false; + } + if (!is_third_party && + !(rule.options() & flat::OptionFlag_APPLIES_TO_FIRST_PARTY)) { + return false; + } + + return true; +} + +const flat::UrlRule* FindMatchAmongCandidates( + const FlatUrlRuleList* candidates, + const GURL& url, + const url::Origin& document_origin, + proto::ElementType element_type, + proto::ActivationType activation_type, + bool is_third_party, + bool disable_generic_rules) { + if (!candidates) + return nullptr; + for (const flat::UrlRule* rule : *candidates) { + DCHECK_NE(rule, nullptr); + DCHECK_NE(rule->url_pattern_type(), flat::UrlPatternType_REGEXP); + if (!DoesRuleFlagsMatch(*rule, element_type, activation_type, + is_third_party)) { + continue; + } + if (!UrlPattern(*rule).MatchesUrl(url)) + continue; + + if (DoesOriginMatchDomainList(document_origin, *rule, + disable_generic_rules)) { + return rule; + } + } + + return nullptr; +} + +// Returns whether the network request matches a UrlPattern |index| represented +// in its FlatBuffers format. |is_third_party| should reflect the relation +// between |url| and |document_origin|. +const flat::UrlRule* FindMatchInFlatUrlPatternIndex( + const flat::UrlPatternIndex& index, + const GURL& url, + const url::Origin& document_origin, + proto::ElementType element_type, + proto::ActivationType activation_type, + bool is_third_party, + bool disable_generic_rules) { + const FlatNGramIndex* hash_table = index.ngram_index(); + const flat::NGramToRules* empty_slot = index.ngram_index_empty_slot(); + DCHECK_NE(hash_table, nullptr); + + NGramHashTableProber prober; + + auto ngrams = CreateNGramExtractor<kNGramSize, uint64_t>( + url.spec(), [](char) { return false; }); + for (uint64_t ngram : ngrams) { + const size_t slot_index = prober.FindSlot( + ngram, base::strict_cast<size_t>(hash_table->size()), + [hash_table, empty_slot](NGram ngram, size_t slot_index) { + const flat::NGramToRules* entry = hash_table->Get(slot_index); + DCHECK_NE(entry, nullptr); + return entry == empty_slot || entry->ngram() == ngram; + }); + DCHECK_LT(slot_index, hash_table->size()); + + const flat::NGramToRules* entry = hash_table->Get(slot_index); + if (entry == empty_slot) + continue; + const flat::UrlRule* rule = FindMatchAmongCandidates( + entry->rule_list(), url, document_origin, element_type, activation_type, + is_third_party, disable_generic_rules); + if (rule) + return rule; + } + + const FlatUrlRuleList* rules = index.fallback_rules(); + return FindMatchAmongCandidates(rules, url, document_origin, element_type, + activation_type, is_third_party, + disable_generic_rules); +} + +} // namespace + +UrlPatternIndexMatcher::UrlPatternIndexMatcher( + const flat::UrlPatternIndex* flat_index) + : flat_index_(flat_index) { + DCHECK(!flat_index || flat_index->n() == kNGramSize); +} + +UrlPatternIndexMatcher::~UrlPatternIndexMatcher() = default; + +const flat::UrlRule* UrlPatternIndexMatcher::FindMatch( + const GURL& url, + const url::Origin& first_party_origin, + proto::ElementType element_type, + proto::ActivationType activation_type, + bool is_third_party, + bool disable_generic_rules) const { + if (!flat_index_ || !url.is_valid()) + return nullptr; + if ((element_type == proto::ELEMENT_TYPE_UNSPECIFIED) == + (activation_type == proto::ACTIVATION_TYPE_UNSPECIFIED)) { + return nullptr; + } + + return FindMatchInFlatUrlPatternIndex(*flat_index_, url, first_party_origin, + element_type, activation_type, + is_third_party, disable_generic_rules); +} + +} // namespace subresource_filter
diff --git a/components/subresource_filter/core/common/url_pattern_index.h b/components/subresource_filter/core/common/url_pattern_index.h new file mode 100644 index 0000000..adeade6 --- /dev/null +++ b/components/subresource_filter/core/common/url_pattern_index.h
@@ -0,0 +1,135 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_INDEX_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_INDEX_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <vector> + +#include "base/macros.h" +#include "base/strings/string_piece.h" +#include "components/subresource_filter/core/common/closed_hash_map.h" +#include "components/subresource_filter/core/common/flat/url_pattern_index_generated.h" +#include "components/subresource_filter/core/common/proto/rules.pb.h" +#include "components/subresource_filter/core/common/uint64_hasher.h" +#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h" + +class GURL; + +namespace url { +class Origin; +} + +namespace subresource_filter { + +// The integer type used to represent N-grams. +using NGram = uint64_t; +// The hasher used for hashing N-grams. +using NGramHasher = Uint64Hasher; +// The hash table probe sequence used both by UrlPatternIndex and its builder. +using NGramHashTableProber = DefaultProber<NGram, NGramHasher>; + +// FlatBuffer offset aliases. +using UrlRuleOffset = flatbuffers::Offset<flat::UrlRule>; +using UrlPatternIndexOffset = flatbuffers::Offset<flat::UrlPatternIndex>; + +constexpr size_t kNGramSize = 5; +static_assert(kNGramSize <= sizeof(NGram), "NGram type is too narrow."); + +// Serializes the |rule| to the FlatBuffer |builder|, and returns an offset to +// it in the resulting buffer. Returns null offset iff the |rule| could not be +// serialized because of unsupported options or it is otherwise invalid. +UrlRuleOffset SerializeUrlRule(const proto::UrlRule& rule, + flatbuffers::FlatBufferBuilder* builder); + +// The class used to construct an index over the URL patterns of a set of URL +// rules. The rules themselves need to be converted to FlatBuffers format by the +// client of this class, as well as persisted into the |flat_builder| that is +// supplied in the constructor. +class UrlPatternIndexBuilder { + public: + explicit UrlPatternIndexBuilder(flatbuffers::FlatBufferBuilder* flat_builder); + ~UrlPatternIndexBuilder(); + + // Adds a UrlRule to the index. The caller should have already persisted the + // rule into the same |flat_builder| by a call to SerializeUrlRule returning a + // non-null |offset|, and should pass in the resulting |offset| here. + void IndexUrlRule(UrlRuleOffset offset); + + // Finalizes construction of the index, serializes it using |flat_builder|, + // and returns an offset to it in the resulting FlatBuffer. + UrlPatternIndexOffset Finish(); + + private: + using MutableUrlRuleList = std::vector<UrlRuleOffset>; + using MutableNGramIndex = + ClosedHashMap<NGram, MutableUrlRuleList, NGramHashTableProber>; + + // Returns an N-gram of the |pattern| encoded into the NGram integer type. The + // N-gram is picked using a greedy heuristic, i.e. the one is chosen which + // corresponds to the shortest list of rules within the index. If there are no + // valid N-grams in the |pattern|, the return value is 0. + NGram GetMostDistinctiveNGram(base::StringPiece pattern); + + // This index contains all non-REGEXP rules that have at least one acceptable + // N-gram. For each given rule, the N-gram used as an index key is picked + // greedily (see GetMostDistinctiveNGram). + MutableNGramIndex ngram_index_; + + // A fallback list that contains all the rules with no acceptable N-gram. + MutableUrlRuleList fallback_rules_; + + // Must outlive this instance. + flatbuffers::FlatBufferBuilder* flat_builder_; + + DISALLOW_COPY_AND_ASSIGN(UrlPatternIndexBuilder); +}; + +// Encapsulates a read-only index built over the URL patterns of a set of URL +// rules, and provides fast matching of network requests against these rules. +class UrlPatternIndexMatcher { + public: + // Creates an instance to access the given |flat_index|. If |flat_index| is + // nullptr, then all requests return no match. + explicit UrlPatternIndexMatcher(const flat::UrlPatternIndex* flat_index); + ~UrlPatternIndexMatcher(); + + // If the index contains one or more UrlRules that match the request, returns + // one of them (it is undefined which one). Otherwise, returns nullptr. + // + // Notes on parameters: + // - |url| should be valid, otherwise the return value is nullptr. + // - Exactly one of |element_type| and |activation_type| should be specified, + // i.e., not equal to *_UNSPECIFIED, otherwise the return value is nullptr. + // - |is_third_party| should be pre-computed by the caller, e.g. using the + // registry_controlled_domains library, to reflect the relation between + // |url| and |first_party_origin|. + // + // A rule is deemed to match the request iff all of the following applies: + // - The |url| matches the rule's UrlPattern (see url_pattern.h). + // - The |first_party_origin| matches the rule's targeted domains list. + // - |element_type| or |activation_type| is among the rule's targeted types. + // - The |is_third_party| bit matches the rule's requirement on the requested + // |url| being first-/third-party w.r.t. its |first_party_origin|. + // - The rule is not generic if |disable_generic_rules| is true. + const flat::UrlRule* FindMatch(const GURL& url, + const url::Origin& first_party_origin, + proto::ElementType element_type, + proto::ActivationType activation_type, + bool is_third_party, + bool disable_generic_rules) const; + + private: + // Must outlive this instance. + const flat::UrlPatternIndex* flat_index_; + + DISALLOW_COPY_AND_ASSIGN(UrlPatternIndexMatcher); +}; + +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_INDEX_H_
diff --git a/components/subresource_filter/core/common/url_rule_test_support.cc b/components/subresource_filter/core/common/url_rule_test_support.cc new file mode 100644 index 0000000..ab6f7f1b --- /dev/null +++ b/components/subresource_filter/core/common/url_rule_test_support.cc
@@ -0,0 +1,56 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/subresource_filter/core/common/url_rule_test_support.h" + +#include "base/logging.h" +#include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace subresource_filter { +namespace testing { + +proto::UrlRule MakeUrlRule(const UrlPattern& url_pattern) { + proto::UrlRule rule; + + rule.set_semantics(proto::RULE_SEMANTICS_BLACKLIST); + rule.set_source_type(proto::SOURCE_TYPE_ANY); + rule.set_element_types(kAllElementTypes); + + rule.set_url_pattern_type(url_pattern.type()); + rule.set_anchor_left(url_pattern.anchor_left()); + rule.set_anchor_right(url_pattern.anchor_right()); + rule.set_match_case(url_pattern.match_case()); + rule.set_url_pattern(url_pattern.url_pattern().as_string()); + + return rule; +} + +void AddDomains(const std::vector<std::string>& domains, proto::UrlRule* rule) { + for (std::string domain_pattern : domains) { + DCHECK(!domain_pattern.empty()); + auto* domain = rule->add_domains(); + if (domain_pattern[0] == '~') { + domain_pattern.erase(0, 1); + domain->set_exclude(true); + } + domain->set_domain(std::move(domain_pattern)); + } +} + +url::Origin GetOrigin(base::StringPiece origin_string) { + return !origin_string.empty() ? url::Origin(GURL(origin_string)) + : url::Origin(); +} + +bool IsThirdParty(const GURL& url, const url::Origin& first_party_origin) { + return first_party_origin.unique() || + !net::registry_controlled_domains::SameDomainOrHost( + url, first_party_origin, + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); +} + +} // namespace testing +} // namespace subresource_filter
diff --git a/components/subresource_filter/core/common/url_rule_test_support.h b/components/subresource_filter/core/common/url_rule_test_support.h new file mode 100644 index 0000000..fef73b9 --- /dev/null +++ b/components/subresource_filter/core/common/url_rule_test_support.h
@@ -0,0 +1,74 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_RULE_TEST_SUPPORT_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_RULE_TEST_SUPPORT_H_ + +#include <string> +#include <vector> + +#include "base/strings/string_piece.h" +#include "components/subresource_filter/core/common/proto/rules.pb.h" +#include "components/subresource_filter/core/common/url_pattern.h" + +class GURL; + +namespace url { +class Origin; +} + +namespace subresource_filter { +namespace testing { + +// Constants ------------------------------------------------------------------- + +constexpr proto::UrlPatternType kSubstring = proto::URL_PATTERN_TYPE_SUBSTRING; + +constexpr proto::AnchorType kAnchorNone = proto::ANCHOR_TYPE_NONE; +constexpr proto::AnchorType kBoundary = proto::ANCHOR_TYPE_BOUNDARY; +constexpr proto::AnchorType kSubdomain = proto::ANCHOR_TYPE_SUBDOMAIN; + +constexpr proto::ElementType kNoElement = proto::ELEMENT_TYPE_UNSPECIFIED; +constexpr proto::ElementType kOther = proto::ELEMENT_TYPE_OTHER; +constexpr proto::ElementType kScript = proto::ELEMENT_TYPE_SCRIPT; +constexpr proto::ElementType kImage = proto::ELEMENT_TYPE_IMAGE; +constexpr proto::ElementType kSubdocument = proto::ELEMENT_TYPE_SUBDOCUMENT; +constexpr proto::ElementType kFont = proto::ELEMENT_TYPE_FONT; +constexpr proto::ElementType kPopup = proto::ELEMENT_TYPE_POPUP; +constexpr proto::ElementType kWebSocket = proto::ELEMENT_TYPE_WEBSOCKET; +constexpr proto::ElementType kAllElementTypes = proto::ELEMENT_TYPE_ALL; + +constexpr proto::ActivationType kNoActivation = + proto::ACTIVATION_TYPE_UNSPECIFIED; +constexpr proto::ActivationType kDocument = proto::ACTIVATION_TYPE_DOCUMENT; +constexpr proto::ActivationType kGenericBlock = + proto::ACTIVATION_TYPE_GENERICBLOCK; + +constexpr proto::SourceType kAnyParty = proto::SOURCE_TYPE_ANY; +constexpr proto::SourceType kThirdParty = proto::SOURCE_TYPE_THIRD_PARTY; +constexpr proto::SourceType kFirstParty = proto::SOURCE_TYPE_FIRST_PARTY; + +// Helpers --------------------------------------------------------------------- + +// Creates a UrlRule with the given |url_pattern|, and all necessary fields +// initialized to defaults. +proto::UrlRule MakeUrlRule(const UrlPattern& url_pattern = UrlPattern()); + +// Parses |domains| and adds them to the domain list of the |rule|. +// +// The |domains| vector should contain non-empty strings. If a string starts +// with '~' then the following part of the string is an exception domain. +void AddDomains(const std::vector<std::string>& domains, proto::UrlRule* rule); + +// Returns the url::Origin parsed from |origin_string|, or the unique origin if +// the string is empty. +url::Origin GetOrigin(base::StringPiece origin_string); + +// Returns whether |url| is third-party resource w.r.t. |first_party_origin|. +bool IsThirdParty(const GURL& url, const url::Origin& first_party_origin); + +} // namespace testing +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_RULE_TEST_SUPPORT_H_
diff --git a/components/suggestions/BUILD.gn b/components/suggestions/BUILD.gn index 9d4a692..6d93d04 100644 --- a/components/suggestions/BUILD.gn +++ b/components/suggestions/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "blacklist_store.cc", "blacklist_store.h", + "features.cc", + "features.h", "image_encoder.h", "image_manager.cc", "image_manager.h",
diff --git a/components/suggestions/features.cc b/components/suggestions/features.cc new file mode 100644 index 0000000..2cac42d4 --- /dev/null +++ b/components/suggestions/features.cc
@@ -0,0 +1,12 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/suggestions/features.h" + +namespace suggestions { + +const base::Feature kUseSuggestionsEvenIfFewFeature{ + "UseSuggestionsEvenIfFew", base::FEATURE_DISABLED_BY_DEFAULT}; + +} // namespace suggestions
diff --git a/components/suggestions/features.h b/components/suggestions/features.h new file mode 100644 index 0000000..8a794594 --- /dev/null +++ b/components/suggestions/features.h
@@ -0,0 +1,18 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SUGGESTIONS_FEATURES_H_ +#define COMPONENTS_SUGGESTIONS_FEATURES_H_ + +#include "base/feature_list.h" + +namespace suggestions { + +// If this feature is enabled, we request and use suggestions even if there are +// only very few of them. +extern const base::Feature kUseSuggestionsEvenIfFewFeature; + +} // namespace suggestions + +#endif // COMPONENTS_SUGGESTIONS_FEATURES_H_
diff --git a/content/browser/payments/payment_app_database.cc b/content/browser/payments/payment_app_database.cc index 4a4644f..00e79cf 100644 --- a/content/browser/payments/payment_app_database.cc +++ b/content/browser/payments/payment_app_database.cc
@@ -203,6 +203,19 @@ base::Passed(std::move(callback)))); } +void PaymentAppDatabase::ClearPaymentInstruments( + const GURL& scope, + ClearPaymentInstrumentsCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + service_worker_context_->FindReadyRegistrationForPattern( + scope, + base::Bind( + &PaymentAppDatabase::DidFindRegistrationToClearPaymentInstruments, + weak_ptr_factory_.GetWeakPtr(), scope, + base::Passed(std::move(callback)))); +} + void PaymentAppDatabase::DidFindRegistrationToWriteManifest( payments::mojom::PaymentAppManifestPtr manifest, const WriteManifestCallback& callback, @@ -525,4 +538,57 @@ : PaymentHandlerStatus::STORAGE_OPERATION_FAILED); } +void PaymentAppDatabase::DidFindRegistrationToClearPaymentInstruments( + const GURL& scope, + ClearPaymentInstrumentsCallback callback, + ServiceWorkerStatusCode status, + scoped_refptr<ServiceWorkerRegistration> registration) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (status != SERVICE_WORKER_OK) { + std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER); + return; + } + + KeysOfPaymentInstruments( + scope, + base::BindOnce(&PaymentAppDatabase::DidGetKeysToClearPaymentInstruments, + weak_ptr_factory_.GetWeakPtr(), registration->id(), + std::move(callback))); +} + +void PaymentAppDatabase::DidGetKeysToClearPaymentInstruments( + int64_t registration_id, + ClearPaymentInstrumentsCallback callback, + const std::vector<std::string>& keys, + PaymentHandlerStatus status) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (status != PaymentHandlerStatus::SUCCESS) { + std::move(callback).Run(PaymentHandlerStatus::NOT_FOUND); + return; + } + + std::vector<std::string> keys_with_prefix; + for (const auto& key : keys) { + keys_with_prefix.push_back(CreatePaymentInstrumentKey(key)); + keys_with_prefix.push_back(CreatePaymentInstrumentKeyInfoKey(key)); + } + + service_worker_context_->ClearRegistrationUserData( + registration_id, keys_with_prefix, + base::Bind(&PaymentAppDatabase::DidClearPaymentInstruments, + weak_ptr_factory_.GetWeakPtr(), + base::Passed(std::move(callback)))); +} + +void PaymentAppDatabase::DidClearPaymentInstruments( + ClearPaymentInstrumentsCallback callback, + ServiceWorkerStatusCode status) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + return std::move(callback).Run(status == SERVICE_WORKER_OK + ? PaymentHandlerStatus::SUCCESS + : PaymentHandlerStatus::NOT_FOUND); +} + } // namespace content
diff --git a/content/browser/payments/payment_app_database.h b/content/browser/payments/payment_app_database.h index 9219e0b..9155f4f8 100644 --- a/content/browser/payments/payment_app_database.h +++ b/content/browser/payments/payment_app_database.h
@@ -44,6 +44,8 @@ base::OnceCallback<void(payments::mojom::PaymentHandlerStatus)>; using WritePaymentInstrumentCallback = base::OnceCallback<void(payments::mojom::PaymentHandlerStatus)>; + using ClearPaymentInstrumentsCallback = + base::OnceCallback<void(payments::mojom::PaymentHandlerStatus)>; explicit PaymentAppDatabase( scoped_refptr<ServiceWorkerContextWrapper> service_worker_context); @@ -69,6 +71,8 @@ const std::string& instrument_key, payments::mojom::PaymentInstrumentPtr instrument, WritePaymentInstrumentCallback callback); + void ClearPaymentInstruments(const GURL& scope, + ClearPaymentInstrumentsCallback callback); private: // WriteManifest callbacks @@ -150,6 +154,20 @@ void DidWritePaymentInstrument(WritePaymentInstrumentCallback callback, ServiceWorkerStatusCode status); + // ClearPaymentInstruments callbacks + void DidFindRegistrationToClearPaymentInstruments( + const GURL& scope, + ClearPaymentInstrumentsCallback callback, + ServiceWorkerStatusCode status, + scoped_refptr<ServiceWorkerRegistration> registration); + void DidGetKeysToClearPaymentInstruments( + int64_t registration_id, + ClearPaymentInstrumentsCallback callback, + const std::vector<std::string>& keys, + payments::mojom::PaymentHandlerStatus status); + void DidClearPaymentInstruments(ClearPaymentInstrumentsCallback callback, + ServiceWorkerStatusCode status); + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; base::WeakPtrFactory<PaymentAppDatabase> weak_ptr_factory_;
diff --git a/content/browser/payments/payment_manager.cc b/content/browser/payments/payment_manager.cc index 0538e22..0503518f 100644 --- a/content/browser/payments/payment_manager.cc +++ b/content/browser/payments/payment_manager.cc
@@ -102,6 +102,14 @@ scope_, instrument_key, std::move(details), callback); } +void PaymentManager::ClearPaymentInstruments( + const ClearPaymentInstrumentsCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + payment_app_context_->payment_app_database()->ClearPaymentInstruments( + scope_, callback); +} + void PaymentManager::OnConnectionError() { DCHECK_CURRENTLY_ON(BrowserThread::IO); payment_app_context_->PaymentManagerHadConnectionError(this);
diff --git a/content/browser/payments/payment_manager.h b/content/browser/payments/payment_manager.h index b0aa75b..0c23de9 100644 --- a/content/browser/payments/payment_manager.h +++ b/content/browser/payments/payment_manager.h
@@ -51,6 +51,8 @@ const std::string& instrument_key, payments::mojom::PaymentInstrumentPtr details, const SetPaymentInstrumentCallback& callback) override; + void ClearPaymentInstruments( + const ClearPaymentInstrumentsCallback& callback) override; // Called when an error is detected on binding_. void OnConnectionError();
diff --git a/content/browser/payments/payment_manager_unittest.cc b/content/browser/payments/payment_manager_unittest.cc index 195d352..07e522c1 100644 --- a/content/browser/payments/payment_manager_unittest.cc +++ b/content/browser/payments/payment_manager_unittest.cc
@@ -71,6 +71,11 @@ *out_status = status; } +void ClearPaymentInstrumentsCallback(PaymentHandlerStatus* out_status, + PaymentHandlerStatus status) { + *out_status = status; +} + } // namespace class PaymentManagerTest : public PaymentAppContentUnitTestBase { @@ -123,6 +128,12 @@ base::RunLoop().RunUntilIdle(); } + void ClearPaymentInstruments(PaymentHandlerStatus* out_status) { + manager_->ClearPaymentInstruments( + base::Bind(&ClearPaymentInstrumentsCallback, out_status)); + base::RunLoop().RunUntilIdle(); + } + private: // Owned by payment_app_context_. PaymentManager* manager_; @@ -294,4 +305,42 @@ ASSERT_EQ("test_key2", keys[2]); } +TEST_F(PaymentManagerTest, ClearPaymentInstruments) { + PaymentHandlerStatus status = PaymentHandlerStatus::NOT_FOUND; + std::vector<std::string> keys; + KeysOfPaymentInstruments(&keys, &status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, status); + ASSERT_EQ(0U, keys.size()); + + { + PaymentHandlerStatus write_status = PaymentHandlerStatus::NOT_FOUND; + SetPaymentInstrument("test_key1", PaymentInstrument::New(), &write_status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, write_status); + } + { + PaymentHandlerStatus write_status = PaymentHandlerStatus::NOT_FOUND; + SetPaymentInstrument("test_key3", PaymentInstrument::New(), &write_status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, write_status); + } + { + PaymentHandlerStatus write_status = PaymentHandlerStatus::NOT_FOUND; + SetPaymentInstrument("test_key2", PaymentInstrument::New(), &write_status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, write_status); + } + + status = PaymentHandlerStatus::NOT_FOUND; + KeysOfPaymentInstruments(&keys, &status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, status); + ASSERT_EQ(3U, keys.size()); + + status = PaymentHandlerStatus::NOT_FOUND; + ClearPaymentInstruments(&status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, status); + + status = PaymentHandlerStatus::NOT_FOUND; + KeysOfPaymentInstruments(&keys, &status); + ASSERT_EQ(PaymentHandlerStatus::SUCCESS, status); + ASSERT_EQ(0U, keys.size()); +} + } // namespace content
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 6acdf23..60867cb 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -85,6 +85,7 @@ void DidBeginMainFrame() override {} void BeginMainFrame(const cc::BeginFrameArgs& args) override {} void BeginMainFrameNotExpectedSoon() override {} + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {} void UpdateLayerTreeHost() override; void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, const gfx::Vector2dF& outer_delta,
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 9733a8c..4e93f94 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -1088,6 +1088,12 @@ compositor_deps_->GetRendererScheduler()->BeginFrameNotExpectedSoon(); } +void RenderWidgetCompositor::BeginMainFrameNotExpectedUntil( + base::TimeTicks time) { + compositor_deps_->GetRendererScheduler()->BeginMainFrameNotExpectedUntil( + time); +} + void RenderWidgetCompositor::UpdateLayerTreeHost() { delegate_->UpdateVisualState(); }
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h index a2692a09..1da6b8b 100644 --- a/content/renderer/gpu/render_widget_compositor.h +++ b/content/renderer/gpu/render_widget_compositor.h
@@ -185,6 +185,7 @@ void DidBeginMainFrame() override; void BeginMainFrame(const cc::BeginFrameArgs& args) override; void BeginMainFrameNotExpectedSoon() override; + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void UpdateLayerTreeHost() override; void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, const gfx::Vector2dF& outer_delta,
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc index 4588f9aa..020f414 100644 --- a/gpu/ipc/service/gpu_init.cc +++ b/gpu/ipc/service/gpu_init.cc
@@ -163,8 +163,22 @@ // Start the GPU watchdog only after anything that is expected to be time // consuming has completed, otherwise the process is liable to be aborted. - if (enable_watchdog && !delayed_watchdog_enable) + if (enable_watchdog && !delayed_watchdog_enable) { watchdog_thread_ = gpu::GpuWatchdogThread::Create(); +#if defined(OS_WIN) + // This is a workaround for an occasional deadlock between watchdog and + // current thread. Watchdog hangs at thread initialization in + // __acrt_thread_attach() and current thread in std::setlocale(...) + // (during InitializeGLOneOff()). Source of the deadlock looks like an old + // UCRT bug that was supposed to be fixed in 10.0.10586 release of UCRT, + // but we might have come accross a not-yet-covered scenario. + // References: + // https://bugs.python.org/issue26624 + // http://stackoverflow.com/questions/35572792/setlocale-stuck-on-windows + auto watchdog_started = watchdog_thread_->WaitUntilThreadStarted(); + DCHECK(watchdog_started); +#endif // OS_WIN + } // Get vendor_id, device_id, driver_version from browser process through // commandline switches.
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc index 07b966c..3b83deb1 100644 --- a/media/audio/audio_input_device.cc +++ b/media/audio/audio_input_device.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" @@ -47,7 +46,7 @@ const double bytes_per_ms_; int current_segment_id_; uint32_t last_buffer_id_; - ScopedVector<media::AudioBus> audio_buses_; + std::vector<std::unique_ptr<media::AudioBus>> audio_buses_; CaptureCallback* capture_callback_; DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); @@ -297,9 +296,8 @@ for (int i = 0; i < total_segments_; ++i) { media::AudioInputBuffer* buffer = reinterpret_cast<media::AudioInputBuffer*>(ptr); - std::unique_ptr<media::AudioBus> audio_bus = - media::AudioBus::WrapMemory(audio_parameters_, buffer->audio); - audio_buses_.push_back(std::move(audio_bus)); + audio_buses_.push_back( + media::AudioBus::WrapMemory(audio_parameters_, buffer->audio)); ptr += segment_length_; } @@ -341,7 +339,7 @@ last_buffer_id_ = buffer->params.id; // Use pre-allocated audio bus wrapping existing block of shared memory. - media::AudioBus* audio_bus = audio_buses_[current_segment_id_]; + media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get(); // Deliver captured data to the client in floating point format and update // the audio delay measurement.
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 498aa1f..e149216 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc
@@ -68,7 +68,8 @@ public: explicit CompareByParams(const DispatcherParams* dispatcher) : dispatcher_(dispatcher) {} - bool operator()(DispatcherParams* dispatcher_in) const { + bool operator()( + const std::unique_ptr<DispatcherParams>& dispatcher_in) const { // We will reuse the existing dispatcher when: // 1) Unified IO is not used, input_params and output_params of the // existing dispatcher are the same as the requested dispatcher. @@ -277,16 +278,14 @@ } } - DispatcherParams* dispatcher_params = - new DispatcherParams(params, output_params, output_device_id); + std::unique_ptr<DispatcherParams> dispatcher_params = + base::MakeUnique<DispatcherParams>(params, output_params, + output_device_id); - AudioOutputDispatchers::iterator it = - std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), - CompareByParams(dispatcher_params)); - if (it != output_dispatchers_.end()) { - delete dispatcher_params; + auto it = std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), + CompareByParams(dispatcher_params.get())); + if (it != output_dispatchers_.end()) return (*it)->dispatcher->CreateStreamProxy(); - } const base::TimeDelta kCloseDelay = base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds); @@ -308,8 +307,8 @@ } dispatcher_params->dispatcher = std::move(dispatcher); - output_dispatchers_.push_back(dispatcher_params); - return dispatcher_params->dispatcher->CreateStreamProxy(); + output_dispatchers_.push_back(std::move(dispatcher_params)); + return output_dispatchers_.back()->dispatcher->CreateStreamProxy(); } void AudioManagerBase::ShowAudioInputSettings() {
diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index 91a9c8c..38748c5 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h
@@ -12,7 +12,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "base/threading/thread.h" #include "build/build_config.h" @@ -166,7 +165,7 @@ FRIEND_TEST_ALL_PREFIXES(AudioManagerTest, AudioDebugRecording); struct DispatcherParams; - typedef ScopedVector<DispatcherParams> AudioOutputDispatchers; + typedef std::vector<std::unique_ptr<DispatcherParams>> AudioOutputDispatchers; class CompareByParams;
diff --git a/net/BUILD.gn b/net/BUILD.gn index 0ba0ee7..e95ef6d 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -172,7 +172,6 @@ "cert/crl_set.h", "cert/ct_known_logs.cc", "cert/ct_known_logs.h", - "cert/ct_known_logs_static-inc.h", "cert/ct_policy_enforcer.cc", "cert/ct_policy_enforcer.h", "cert/ct_policy_status.h", @@ -360,6 +359,7 @@ ":net_resources", "//base", "//net/base/registry_controlled_domains", + "//net/data/ssl/certificate_transparency:ct_log_list", "//net/data/ssl/wosign:wosign_domains", "//third_party/protobuf:protobuf_lite", "//url:url_features", @@ -4905,6 +4905,7 @@ "//crypto:platform", "//crypto:test_support", "//net/base/registry_controlled_domains", + "//net/data/ssl/certificate_transparency:ct_log_list", "//net/http:transport_security_state_unittest_data", "//testing/gmock", "//testing/gtest",
diff --git a/net/cert/ct_known_logs.cc b/net/cert/ct_known_logs.cc index cca1fbe..a1e80c7 100644 --- a/net/cert/ct_known_logs.cc +++ b/net/cert/ct_known_logs.cc
@@ -25,7 +25,7 @@ namespace { -#include "net/cert/ct_known_logs_static-inc.h" +#include "net/data/ssl/certificate_transparency/log_list-inc.cc" } // namespace
diff --git a/net/cert/ct_known_logs_static-inc.h b/net/cert/ct_known_logs_static-inc.h deleted file mode 100644 index ac86f5a..0000000 --- a/net/cert/ct_known_logs_static-inc.h +++ /dev/null
@@ -1,231 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -struct CTLogInfo { - // The DER-encoded SubjectPublicKeyInfo for the log. - const char* log_key; - // The length, in bytes, of |log_key|. - size_t log_key_length; - // The user-friendly log name. - // Note: This will not be translated. - const char* log_name; - // The HTTPS API endpoint for the log. - // Note: Trailing slashes should be included. - const char* log_url; - // The DNS API endpoint for the log. - // This is used as the parent domain for all queries about the log. - // If empty, CT DNS queries are not supported for the log. This will prevent - // retrieval of inclusion proofs over DNS for SCTs from the log. - // https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md. - const char* log_dns_domain; -}; - -// The set of all presently-qualifying CT logs. -// Google provides DNS frontends for all of the logs. -const CTLogInfo kCTLogList[] = { - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x7d\xa8\x4b\x12\x29\x80\xa3" - "\x3d\xad\xd3\x5a\x77\xb8\xcc\xe2\x88\xb3\xa5\xfd\xf1\xd3\x0c\xcd\x18" - "\x0c\xe8\x41\x46\xe8\x81\x01\x1b\x15\xe1\x4b\xf1\x1b\x62\xdd\x36\x0a" - "\x08\x18\xba\xed\x0b\x35\x84\xd0\x9e\x40\x3c\x2d\x9e\x9b\x82\x65\xbd" - "\x1f\x04\x10\x41\x4c\xa0", - 91, "Google 'Pilot' log", "https://ct.googleapis.com/pilot/", - "pilot.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xd7\xf4\xcc\x69\xb2\xe4\x0e" - "\x90\xa3\x8a\xea\x5a\x70\x09\x4f\xef\x13\x62\xd0\x8d\x49\x60\xff\x1b" - "\x40\x50\x07\x0c\x6d\x71\x86\xda\x25\x49\x8d\x65\xe1\x08\x0d\x47\x34" - "\x6b\xbd\x27\xbc\x96\x21\x3e\x34\xf5\x87\x76\x31\xb1\x7f\x1d\xc9\x85" - "\x3b\x0d\xf7\x1f\x3f\xe9", - 91, "Google 'Aviator' log", "https://ct.googleapis.com/aviator/", - "aviator.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x02\x46\xc5\xbe\x1b\xbb\x82" - "\x40\x16\xe8\xc1\xd2\xac\x19\x69\x13\x59\xf8\xf8\x70\x85\x46\x40\xb9" - "\x38\xb0\x23\x82\xa8\x64\x4c\x7f\xbf\xbb\x34\x9f\x4a\x5f\x28\x8a\xcf" - "\x19\xc4\x00\xf6\x36\x06\x93\x65\xed\x4c\xf5\xa9\x21\x62\x5a\xd8\x91" - "\xeb\x38\x24\x40\xac\xe8", - 91, "DigiCert Log Server", "https://ct1.digicert-ct.com/log/", - "digicert.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x20\x5b\x18\xc8\x3c\xc1\x8b" - "\xb3\x31\x08\x00\xbf\xa0\x90\x57\x2b\xb7\x47\x8c\x6f\xb5\x68\xb0\x8e" - "\x90\x78\xe9\xa0\x73\xea\x4f\x28\x21\x2e\x9c\xc0\xf4\x16\x1b\xaa\xf9" - "\xd5\xd7\xa9\x80\xc3\x4e\x2f\x52\x3c\x98\x01\x25\x46\x24\x25\x28\x23" - "\x77\x2d\x05\xc2\x40\x7a", - 91, "Google 'Rocketeer' log", "https://ct.googleapis.com/rocketeer/", - "rocketeer.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x96\xea\xac\x1c\x46\x0c\x1b" - "\x55\xdc\x0d\xfc\xb5\x94\x27\x46\x57\x42\x70\x3a\x69\x18\xe2\xbf\x3b" - "\xc4\xdb\xab\xa0\xf4\xb6\x6c\xc0\x53\x3f\x4d\x42\x10\x33\xf0\x58\x97" - "\x8f\x6b\xbe\x72\xf4\x2a\xec\x1c\x42\xaa\x03\x2f\x1a\x7e\x28\x35\x76" - "\x99\x08\x3d\x21\x14\x86", - 91, "Symantec log", "https://ct.ws.symantec.com/", - "symantec.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xea\x95\x9e\x02\xff\xee\xf1" - "\x33\x6d\x4b\x87\xbc\xcd\xfd\x19\x17\x62\xff\x94\xd3\xd0\x59\x07\x3f" - "\x02\x2d\x1c\x90\xfe\xc8\x47\x30\x3b\xf1\xdd\x0d\xb8\x11\x0c\x5d\x1d" - "\x86\xdd\xab\xd3\x2b\x46\x66\xfb\x6e\x65\xb7\x3b\xfd\x59\x68\xac\xdf" - "\xa6\xf8\xce\xd2\x18\x4d", - 91, "Symantec 'Vega' log", "https://vega.ws.symantec.com/", - "symantec-vega.ct.googleapis.com"}, - {"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01" - "\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xbf" - "\xb5\x08\x61\x9a\x29\x32\x04\xd3\x25\x63\xe9\xd8\x85\xe1\x86\xe0\x1f" - "\xd6\x5e\x9a\xf7\x33\x3b\x80\x1b\xe7\xb6\x3e\x5f\x2d\xa1\x66\xf6\x95" - "\x4a\x84\xa6\x21\x56\x79\xe8\xf7\x85\xee\x5d\xe3\x7c\x12\xc0\xe0\x89" - "\x22\x09\x22\x3e\xba\x16\x95\x06\xbd\xa8\xb9\xb1\xa9\xb2\x7a\xd6\x61" - "\x2e\x87\x11\xb9\x78\x40\x89\x75\xdb\x0c\xdc\x90\xe0\xa4\x79\xd6\xd5" - "\x5e\x6e\xd1\x2a\xdb\x34\xf4\x99\x3f\x65\x89\x3b\x46\xc2\x29\x2c\x15" - "\x07\x1c\xc9\x4b\x1a\x54\xf8\x6c\x1e\xaf\x60\x27\x62\x0a\x65\xd5\x9a" - "\xb9\x50\x36\x16\x6e\x71\xf6\x1f\x01\xf7\x12\xa7\xfc\xbf\xf6\x21\xa3" - "\x29\x90\x86\x2d\x77\xde\xbb\x4c\xd4\xcf\xfd\xd2\xcf\x82\x2c\x4d\xd4" - "\xf2\xc2\x2d\xac\xa9\xbe\xea\xc3\x19\x25\x43\xb2\xe5\x9a\x6c\x0d\xc5" - "\x1c\xa5\x8b\xf7\x3f\x30\xaf\xb9\x01\x91\xb7\x69\x12\x12\xe5\x83\x61" - "\xfe\x34\x00\xbe\xf6\x71\x8a\xc7\xeb\x50\x92\xe8\x59\xfe\x15\x91\xeb" - "\x96\x97\xf8\x23\x54\x3f\x2d\x8e\x07\xdf\xee\xda\xb3\x4f\xc8\x3c\x9d" - "\x6f\xdf\x3c\x2c\x43\x57\xa1\x47\x0c\x91\x04\xf4\x75\x4d\xda\x89\x81" - "\xa4\x14\x06\x34\xb9\x98\xc3\xda\xf1\xfd\xed\x33\x36\xd3\x16\x2d\x35" - "\x02\x03\x01\x00\x01", - 294, "CNNIC CT log", "https://ctserver.cnnic.cn/", - "cnnic.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xcc\x11\x88\x7b\x2d\x66\xcb" - "\xae\x8f\x4d\x30\x66\x27\x19\x25\x22\x93\x21\x46\xb4\x2f\x01\xd3\xc6" - "\xf9\x2b\xd5\xc8\xba\x73\x9b\x06\xa2\xf0\x8a\x02\x9c\xd0\x6b\x46\x18" - "\x30\x85\xba\xe9\x24\x8b\x0e\xd1\x5b\x70\x28\x0c\x7e\xf1\x3a\x45\x7f" - "\x5a\xf3\x82\x42\x60\x31", - 91, "WoSign log", "https://ctlog.wosign.com/", - "wosign1.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x48\xf3\x59\xf3\xf6\x05\x18" - "\xd3\xdb\xb2\xed\x46\x7e\xcf\xc8\x11\xb5\x57\xb1\xa8\xd6\x4c\xe6\x9f" - "\xb7\x4a\x1a\x14\x86\x43\xa9\x48\xb0\xcb\x5a\x3f\x3c\x4a\xca\xdf\xc4" - "\x82\x14\x55\x9a\xf8\xf7\x8e\x40\x55\xdc\xf4\xd2\xaf\xea\x75\x74\xfb" - "\x4e\x7f\x60\x86\x2e\x51", - 91, "StartCom CT log", "https://ct.startssl.com/", - "startcom1.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x12\x6c\x86\x0e\xf6\x17\xb1" - "\x12\x6c\x37\x25\xd2\xad\x87\x3d\x0e\x31\xec\x21\xad\xb1\xcd\xbe\x14" - "\x47\xb6\x71\x56\x85\x7a\x9a\xb7\x3d\x89\x90\x7b\xc6\x32\x3a\xf8\xda" - "\xce\x8b\x01\xfe\x3f\xfc\x71\x91\x19\x8e\x14\x6e\x89\x7a\x5d\xb4\xab" - "\x7e\xe1\x4e\x1e\x7c\xac", - 91, "Google 'Skydiver' log", "https://ct.googleapis.com/skydiver/", - "skydiver.ct.googleapis.com"}, - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x4e\xd2\xbc\xbf\xb3\x08\x0a" - "\xf7\xb9\xea\xa4\xc7\x1c\x38\x61\x04\xeb\x95\xe0\x89\x54\x68\x44\xb1" - "\x66\xbc\x82\x7e\x4f\x50\x6c\x6f\x5c\xa3\xf0\xaa\x3e\xf4\xec\x80\xf0" - "\xdb\x0a\x9a\x7a\xa0\x5b\x72\x00\x7c\x25\x0e\x19\xef\xaf\xb2\x62\x8d" - "\x74\x43\xf4\x26\xf6\x14", - 91, "Google 'Icarus' log", "https://ct.googleapis.com/icarus/", - "icarus.ct.googleapis.com"}, - {"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01" - "\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xac" - "\xcf\x2f\x4b\x70\xac\xf1\x0d\x96\xbf\xe8\x0a\xfe\x44\x9d\xd4\x8c\x17" - "\x9d\xc3\x9a\x10\x11\x84\x13\xed\x8c\xf9\x37\x6d\x83\xe4\x00\x6f\xb1" - "\x4b\xc0\xa6\x89\xc7\x61\x8f\x9a\x34\xbb\x56\x52\xca\x03\x56\x50\xef" - "\x24\x7f\x4b\x49\xe9\x35\x81\xdd\xf0\xe7\x17\xf5\x72\xd2\x23\xc5\xe3" - "\x13\x7f\xd7\x8e\x78\x35\x8f\x49\xde\x98\x04\x8a\x63\xaf\xad\xa2\x39" - "\x70\x95\x84\x68\x4b\x91\x33\xfe\x4c\xe1\x32\x17\xc2\xf2\x61\xb8\x3a" - "\x8d\x39\x7f\xd5\x95\x82\x3e\x56\x19\x50\x45\x6f\xcb\x08\x33\x0d\xd5" - "\x19\x42\x08\x1a\x48\x42\x10\xf1\x68\xc3\xc3\x41\x13\xcb\x0d\x1e\xdb" - "\x02\xb7\x24\x7a\x51\x96\x6e\xbc\x08\xea\x69\xaf\x6d\xef\x92\x98\x8e" - "\x55\xf3\x65\xe5\xe8\x9c\xbe\x1a\x47\x60\x30\x7d\x7a\x80\xad\x56\x83" - "\x7a\x93\xc3\xae\x93\x2b\x6a\x28\x8a\xa6\x5f\x63\x19\x0c\xbe\x7c\x7b" - "\x21\x63\x41\x38\xb7\xf7\xe8\x76\x73\x6b\x85\xcc\xbc\x72\x2b\xc1\x52" - "\xd0\x5b\x5d\x31\x4e\x9d\x2a\xf3\x4d\x9b\x64\x14\x99\x26\xc6\x71\xf8" - "\x7b\xf8\x44\xd5\xe3\x23\x20\xf3\x0a\xd7\x8b\x51\x3e\x72\x80\xd2\x78" - "\x78\x35\x2d\x4a\xe7\x40\x99\x11\x95\x34\xd4\x2f\x7f\xf9\x5f\x35\x37" - "\x02\x03\x01\x00\x01", - 294, "PuChuangSiDa CT Log 1", "https://www.certificatetransparency.cn/ct/", - "puchuangsida1.ct.googleapis.com"}}; - -// Information related to previously-qualified, but now disqualified, CT -// logs. -struct DisqualifiedCTLogInfo { - // The ID of the log (the SHA-256 hash of |log_info.log_key|. - const char log_id[33]; - - const CTLogInfo log_info; - - // The offset from the Unix Epoch of when the log was disqualified. - // SCTs embedded in pre-certificates after this date should not count - // towards any uniqueness/freshness requirements. - const base::TimeDelta disqualification_date; -}; - -// The set of all disqualified logs, sorted by |log_id|. -const DisqualifiedCTLogInfo kDisqualifiedCTLogList[] = { - { - "\x74\x61\xb4\xa0\x9c\xfb\x3d\x41\xd7\x51\x59\x57\x5b\x2e\x76\x49\xa4" - "\x45\xa8\xd2\x77\x09\xb0\xcc\x56\x4a\x64\x82\xb7\xeb\x41\xa3", - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x27\x64\x39\x0c\x2d\xdc\x50" - "\x18\xf8\x21\x00\xa2\x0e\xed\x2c\xea\x3e\x75\xba\x9f\x93\x64\x09\x00" - "\x11\xc4\x11\x17\xab\x5c\xcf\x0f\x74\xac\xb5\x97\x90\x93\x00\x5b\xb8" - "\xeb\xf7\x27\x3d\xd9\xb2\x0a\x81\x5f\x2f\x0d\x75\x38\x94\x37\x99\x1e" - "\xf6\x07\x76\xe0\xee\xbe", - 91, "Izenpe log", "https://ct.izenpe.com/", - "izenpe1.ct.googleapis.com"}, - // 2016-05-30 00:00:00 UTC - base::TimeDelta::FromSeconds(1464566400), - }, - { - "\xac\x3b\x9a\xed\x7f\xa9\x67\x47\x57\x15\x9e\x6d\x7d\x57\x56\x72\xf9" - "\xd9\x81\x00\x94\x1e\x9b\xde\xff\xec\xa1\x31\x3b\x75\x78\x2d", - {"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01" - "\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2" - "\x5a\x48\x1f\x17\x52\x95\x35\xcb\xa3\x5b\x3a\x1f\x53\x82\x76\x94\xa3" - "\xff\x80\xf2\x1c\x37\x3c\xc0\xb1\xbd\xc1\x59\x8b\xab\x2d\x65\x93\xd7" - "\xf3\xe0\x04\xd5\x9a\x6f\xbf\xd6\x23\x76\x36\x4f\x23\x99\xcb\x54\x28" - "\xad\x8c\x15\x4b\x65\x59\x76\x41\x4a\x9c\xa6\xf7\xb3\x3b\x7e\xb1\xa5" - "\x49\xa4\x17\x51\x6c\x80\xdc\x2a\x90\x50\x4b\x88\x24\xe9\xa5\x12\x32" - "\x93\x04\x48\x90\x02\xfa\x5f\x0e\x30\x87\x8e\x55\x76\x05\xee\x2a\x4c" - "\xce\xa3\x6a\x69\x09\x6e\x25\xad\x82\x76\x0f\x84\x92\xfa\x38\xd6\x86" - "\x4e\x24\x8f\x9b\xb0\x72\xcb\x9e\xe2\x6b\x3f\xe1\x6d\xc9\x25\x75\x23" - "\x88\xa1\x18\x58\x06\x23\x33\x78\xda\x00\xd0\x38\x91\x67\xd2\xa6\x7d" - "\x27\x97\x67\x5a\xc1\xf3\x2f\x17\xe6\xea\xd2\x5b\xe8\x81\xcd\xfd\x92" - "\x68\xe7\xf3\x06\xf0\xe9\x72\x84\xee\x01\xa5\xb1\xd8\x33\xda\xce\x83" - "\xa5\xdb\xc7\xcf\xd6\x16\x7e\x90\x75\x18\xbf\x16\xdc\x32\x3b\x6d\x8d" - "\xab\x82\x17\x1f\x89\x20\x8d\x1d\x9a\xe6\x4d\x23\x08\xdf\x78\x6f\xc6" - "\x05\xbf\x5f\xae\x94\x97\xdb\x5f\x64\xd4\xee\x16\x8b\xa3\x84\x6c\x71" - "\x2b\xf1\xab\x7f\x5d\x0d\x32\xee\x04\xe2\x90\xec\x41\x9f\xfb\x39\xc1" - "\x02\x03\x01\x00\x01", - 294, "Venafi log", "https://ctlog.api.venafi.com/", - "venafi.ct.googleapis.com"}, - // 2017-02-28 18:42:26 UTC - base::TimeDelta::FromSeconds(1488307346), - }, - { - "\xcd\xb5\x17\x9b\x7f\xc1\xc0\x46\xfe\xea\x31\x13\x6a\x3f\x8f\x00\x2e" - "\x61\x82\xfa\xf8\x89\x6f\xec\xc8\xb2\xf5\xb5\xab\x60\x49\x00", - {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86" - "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x0b\x23\xcb\x85\x62\x98\x61" - "\x48\x04\x73\xeb\x54\x5d\xf3\xd0\x07\x8c\x2d\x19\x2d\x8c\x36\xf5\xeb" - "\x8f\x01\x42\x0a\x7c\x98\x26\x27\xc1\xb5\xdd\x92\x93\xb0\xae\xf8\x9b" - "\x3d\x0c\xd8\x4c\x4e\x1d\xf9\x15\xfb\x47\x68\x7b\xba\x66\xb7\x25\x9c" - "\xd0\x4a\xc2\x66\xdb\x48", - 91, "Certly.IO log", "https://log.certly.io/", - "certly.ct.googleapis.com"}, - // 2016-04-15 00:00:00 UTC - base::TimeDelta::FromSeconds(1460678400), - }, -}; - -// The list is sorted. -const char kGoogleLogIDs[][33] = { - "\x29\x3c\x51\x96\x54\xc8\x39\x65\xba\xaa\x50\xfc\x58\x07\xd4\xb7\x6f" - "\xbf\x58\x7a\x29\x72\xdc\xa4\xc3\x0c\xf4\xe5\x45\x47\xf4\x78", - "\x68\xf6\x98\xf8\x1f\x64\x82\xbe\x3a\x8c\xee\xb9\x28\x1d\x4c\xfc\x71" - "\x51\x5d\x67\x93\xd4\x44\xd1\x0a\x67\xac\xbb\x4f\x4f\xfb\xc4", - "\xa4\xb9\x09\x90\xb4\x18\x58\x14\x87\xbb\x13\xa2\xcc\x67\x70\x0a\x3c" - "\x35\x98\x04\xf9\x1b\xdf\xb8\xe3\x77\xcd\x0e\xc8\x0d\xdc\x10", - "\xbb\xd9\xdf\xbc\x1f\x8a\x71\xb5\x93\x94\x23\x97\xaa\x92\x7b\x47\x38" - "\x57\x95\x0a\xab\x52\xe8\x1a\x90\x96\x64\x36\x8e\x1e\xd1\x85", - "\xee\x4b\xbd\xb7\x75\xce\x60\xba\xe1\x42\x69\x1f\xab\xe1\x9e\x66\xa3" - "\x0f\x7e\x5f\xb0\x72\xd8\x83\x00\xc4\x7b\x89\x7a\xa8\xfd\xcb"};
diff --git a/net/cert/ct_known_logs_unittest.cc b/net/cert/ct_known_logs_unittest.cc index f5e937a..59a074e7 100644 --- a/net/cert/ct_known_logs_unittest.cc +++ b/net/cert/ct_known_logs_unittest.cc
@@ -15,9 +15,7 @@ namespace net { namespace { - -#include "net/cert/ct_known_logs_static-inc.h" - +#include "net/data/ssl/certificate_transparency/log_list-inc.cc" } // namespace TEST(CTKnownLogsTest, GoogleIDsAreSorted) {
diff --git a/net/data/ssl/certificate_transparency/BUILD.gn b/net/data/ssl/certificate_transparency/BUILD.gn new file mode 100644 index 0000000..8c5eb6c3 --- /dev/null +++ b/net/data/ssl/certificate_transparency/BUILD.gn
@@ -0,0 +1,18 @@ +# Copyright (c) 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +action_foreach("ct_log_list") { + script = "//net/tools/ct_log_list/make_ct_known_logs_list.py" + sources = [ + "log_list.json", + ] + outputs = [ + "${target_gen_dir}/{{source_name_part}}-inc.cc", + ] + args = [ + "{{source}}", + rebase_path("${target_gen_dir}/{{source_name_part}}-inc.cc", + root_build_dir), + ] +}
diff --git a/net/data/ssl/certificate_transparency/log_list.json b/net/data/ssl/certificate_transparency/log_list.json new file mode 100644 index 0000000..97d6df3c0 --- /dev/null +++ b/net/data/ssl/certificate_transparency/log_list.json
@@ -0,0 +1,205 @@ +{ + "logs": [ + { + "description": "Google 'Aviator' log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==", + "url": "ct.googleapis.com/aviator/", + "maximum_merge_delay": 86400, + "operated_by": [ + 0 + ], + "final_sth": { + "tree_size": 46466472, + "timestamp": 1480512258330, + "sha256_root_hash": "LcGcZRsm+LGYmrlyC5LXhV1T6OD8iH5dNlb0sEJl9bA=", + "tree_head_signature": "BAMASDBGAiEA/M0Nvt77aNe+9eYbKsv6rRpTzFTKa5CGqb56ea4hnt8CIQCJDE7pL6xgAewMd5i3G1lrBWgFooT2kd3+zliEz5Rw8w==" + }, + "dns_api_endpoint": "aviator.ct.googleapis.com" + }, + { + "description": "Google 'Icarus' log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETtK8v7MICve56qTHHDhhBOuV4IlUaESxZryCfk9QbG9co/CqPvTsgPDbCpp6oFtyAHwlDhnvr7JijXRD9Cb2FA==", + "url": "ct.googleapis.com/icarus/", + "maximum_merge_delay": 86400, + "operated_by": [ + 0 + ], + "dns_api_endpoint": "icarus.ct.googleapis.com" + }, + { + "description": "Google 'Pilot' log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==", + "url": "ct.googleapis.com/pilot/", + "maximum_merge_delay": 86400, + "operated_by": [ + 0 + ], + "dns_api_endpoint": "pilot.ct.googleapis.com" + }, + { + "description": "Google 'Rocketeer' log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==", + "url": "ct.googleapis.com/rocketeer/", + "maximum_merge_delay": 86400, + "operated_by": [ + 0 + ], + "dns_api_endpoint": "rocketeer.ct.googleapis.com" + }, + { + "description": "Google 'Skydiver' log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEmyGDvYXsRJsNyXSrYc9DjHsIa2xzb4UR7ZxVoV6mrc9iZB7xjI6+NrOiwH+P/xxkRmOFG6Jel20q37hTh58rA==", + "url": "ct.googleapis.com/skydiver/", + "maximum_merge_delay": 86400, + "operated_by": [ + 0 + ], + "dns_api_endpoint": "skydiver.ct.googleapis.com" + }, + { + "description": "DigiCert Log Server", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==", + "url": "ct1.digicert-ct.com/log/", + "maximum_merge_delay": 86400, + "operated_by": [ + 1 + ], + "dns_api_endpoint": "digicert.ct.googleapis.com" + }, + { + "description": "Symantec log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==", + "url": "ct.ws.symantec.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "symantec.ct.googleapis.com" + }, + { + "description": "Symantec 'Vega' log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6pWeAv/u8TNtS4e8zf0ZF2L/lNPQWQc/Ai0ckP7IRzA78d0NuBEMXR2G3avTK0Zm+25ltzv9WWis36b4ztIYTQ==", + "url": "vega.ws.symantec.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "symantec-vega.ct.googleapis.com" + }, + { + "description": "Certly.IO log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==", + "url": "log.certly.io/", + "maximum_merge_delay": 86400, + "operated_by": [ + 3 + ], + "disqualified_at": 1460678400, + "dns_api_endpoint": "certly.ct.googleapis.com" + }, + { + "description": "Izenpe log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==", + "url": "ct.izenpe.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 4 + ], + "disqualified_at": 1464566400, + "dns_api_endpoint": "izenpe1.ct.googleapis.com" + }, + { + "description": "WoSign log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBGIey1my66PTTBmJxklIpMhRrQvAdPG+SvVyLpzmwai8IoCnNBrRhgwhbrpJIsO0VtwKAx+8TpFf1rzgkJgMQ==", + "url": "ctlog.wosign.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 5 + ], + "dns_api_endpoint": "wosign1.ct.googleapis.com" + }, + { + "description": "Venafi log", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB", + "url": "ctlog.api.venafi.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 6 + ], + "disqualified_at": 1488307346, + "dns_api_endpoint": "venafi.ct.googleapis.com" + }, + { + "description": "CNNIC CT log", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7UIYZopMgTTJWPp2IXhhuAf1l6a9zM7gBvntj5fLaFm9pVKhKYhVnno94XuXeN8EsDgiSIJIj66FpUGvai5samyetZhLocRuXhAiXXbDNyQ4KR51tVebtEq2zT0mT9liTtGwiksFQccyUsaVPhsHq9gJ2IKZdWauVA2Fm5x9h8B9xKn/L/2IaMpkIYtd967TNTP/dLPgixN1PLCLaypvurDGSVDsuWabA3FHKWL9z8wr7kBkbdpEhLlg2H+NAC+9nGKx+tQkuhZ/hWR65aX+CNUPy2OB9/u2rNPyDydb988LENXoUcMkQT0dU3aiYGkFAY0uZjD2vH97TM20xYtNQIDAQAB", + "url": "ctserver.cnnic.cn/", + "maximum_merge_delay": 86400, + "operated_by": [ + 7 + ], + "dns_api_endpoint": "cnnic.ct.googleapis.com" + }, + { + "description": "StartCom log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESPNZ8/YFGNPbsu1Gfs/IEbVXsajWTOaft0oaFIZDqUiwy1o/PErK38SCFFWa+PeOQFXc9NKv6nV0+05/YIYuUQ==", + "url": "ct.startssl.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 8 + ], + "dns_api_endpoint": "startcom1.ct.googleapis.com" + }, + { + "description": "PuChuangSiDa CT log", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArM8vS3Cs8Q2Wv+gK/kSd1IwXncOaEBGEE+2M+Tdtg+QAb7FLwKaJx2GPmjS7VlLKA1ZQ7yR/S0npNYHd8OcX9XLSI8XjE3/Xjng1j0nemASKY6+tojlwlYRoS5Ez/kzhMhfC8mG4Oo05f9WVgj5WGVBFb8sIMw3VGUIIGkhCEPFow8NBE8sNHtsCtyR6UZZuvAjqaa9t75KYjlXzZeXonL4aR2AwfXqArVaDepPDrpMraiiKpl9jGQy+fHshY0E4t/fodnNrhcy8civBUtBbXTFOnSrzTZtkFJkmxnH4e/hE1eMjIPMK14tRPnKA0nh4NS1K50CZEZU01C9/+V81NwIDAQAB", + "url": "www.certificatetransparency.cn/ct/", + "maximum_merge_delay": 86400, + "operated_by": [ + 9 + ], + "dns_api_endpoint": "puchuangsida1.ct.googleapis.com" + } + ], + "operators": [ + { + "name": "Google", + "id": 0 + }, + { + "name": "DigiCert", + "id": 1 + }, + { + "name": "Symantec", + "id": 2 + }, + { + "name": "Certly", + "id": 3 + }, + { + "name": "Izenpe", + "id": 4 + }, + { + "name": "Wosign", + "id": 5 + }, + { + "name": "Venafi", + "id": 6 + }, + { + "name": "CNNIC", + "id": 7 + }, + { + "name": "StartSSL", + "id": 8 + }, + { + "name": "Beijing PuChuangSiDa Technology Ltd.", + "id": 9 + } + ] +} \ No newline at end of file
diff --git a/net/tools/ct_log_list/PRESUBMIT.py b/net/tools/ct_log_list/PRESUBMIT.py new file mode 100644 index 0000000..ff9bf5c1 --- /dev/null +++ b/net/tools/ct_log_list/PRESUBMIT.py
@@ -0,0 +1,34 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +"""Chromium presubmit script for src/net/tools/ct_log_list.""" + + +def _RunMakeCTLogListTests(input_api, output_api): + """Runs make_ct_known_logs_list unittests if related files were modified.""" + files = ('net/tools/ct_log_list/make_ct_known_logs_list.py', + 'net/tools/ct_log_list/make_ct_known_logs_list_unittest.py', + 'net/data/ssl/certificate_transparency/log_list.json') + if not any(f in input_api.LocalPaths() for f in files): + return [] + test_path = input_api.os_path.join(input_api.PresubmitLocalPath(), + 'make_ct_known_logs_list_unittest.py') + cmd_name = 'make_ct_known_logs_list_unittest' + cmd = [input_api.python_executable, test_path] + test_cmd = input_api.Command( + name=cmd_name, + cmd=cmd, + kwargs={}, + message=output_api.PresubmitPromptWarning) + return input_api.RunTests([test_cmd]) + + +def CheckChangeOnUpload(input_api, output_api): + return _RunMakeCTLogListTests(input_api, output_api) + + +def CheckChangeOnCommit(input_api, output_api): + return _RunMakeCTLogListTests(input_api, output_api) +
diff --git a/net/tools/ct_log_list/make_ct_known_logs_list.py b/net/tools/ct_log_list/make_ct_known_logs_list.py new file mode 100755 index 0000000..01017d7e --- /dev/null +++ b/net/tools/ct_log_list/make_ct_known_logs_list.py
@@ -0,0 +1,222 @@ +#!/usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Generate a C++ file containing information on all accepted CT logs.""" + +import base64 +import hashlib +import json +import math +import sys + + +def _write_cpp_header(f): + f.write("// This file is auto-generated, DO NOT EDIT.\n\n") + + +def _write_log_info_struct_definition(f): + f.write( + "struct CTLogInfo {\n" + " // The DER-encoded SubjectPublicKeyInfo for the log.\n" + " const char* log_key;\n" + " // The length, in bytes, of |log_key|.\n" + " size_t log_key_length;\n" + " // The user-friendly log name.\n" + " // Note: This will not be translated.\n" + " const char* log_name;\n" + " // The HTTPS API endpoint for the log.\n" + " // Note: Trailing slashes should be included.\n" + " const char* log_url;\n" + " // The DNS API endpoint for the log.\n" + " // This is used as the parent domain for all queries about the " + "log.\n // If empty, CT DNS queries are not supported for the log. " + "This will prevent\n // retrieval of inclusion proofs over DNS for " + "SCTs from the log.\n" + " // https://github.com/google/certificate-transparency-rfcs/blob/" + "master/dns/draft-ct-over-dns.md.\n" + " const char* log_dns_domain;\n" + "};\n\n" + ) + + +def _write_disqualified_log_info_struct_definition(f): + f.write( + "// Information related to previously-qualified, but now disqualified," + "\n" + "// CT logs.\n" + "struct DisqualifiedCTLogInfo {\n" + " // The ID of the log (the SHA-256 hash of |log_info.log_key|.\n" + " const char log_id[33];\n" + " const CTLogInfo log_info;\n" + " // The offset from the Unix Epoch of when the log was disqualified." + "\n" + " // SCTs embedded in pre-certificates after this date should not" + " count\n" + " // towards any uniqueness/freshness requirements.\n" + " const base::TimeDelta disqualification_date;\n" + "};\n\n") + + +def _split_and_hexify_binary_data(bin_data): + """Pretty-prints, in hex, the given bin_data.""" + hex_data = "".join(["\\x%.2x" % ord(c) for c in bin_data]) + # line_width % 4 must be 0 to avoid splitting the hex-encoded data + # across '\' which will escape the quotation marks. + line_width = 68 + assert line_width % 4 == 0 + num_splits = int(math.ceil(len(hex_data) / float(line_width))) + return ['"%s"' % hex_data[i * line_width:(i + 1) * line_width] + for i in range(num_splits)] + + +def _get_log_ids_array(log_ids, array_name): + num_logs = len(log_ids) + log_ids.sort() + log_id_length = len(log_ids[0]) + 1 + log_id_code = [ + "// The list is sorted.\n", + "const char %s[][%d] = {\n" % (array_name, log_id_length)] + for i in range(num_logs): + split_hex_id = _split_and_hexify_binary_data(log_ids[i]) + s = " %s" % ("\n ".join(split_hex_id)) + if (i < num_logs - 1): + s += ',\n' + log_id_code.append(s) + log_id_code.append('};\n\n') + return log_id_code + + + +def _find_google_operator_id(json_log_list): + goog_operator = [op for op in json_log_list["operators"] + if op["name"] == "Google"] + if len(goog_operator) != 1: + raise RuntimeError("Google operator ID not found.") + + return goog_operator[0]["id"] + + +def _get_log_ids_for_operator(logs, operator_id): + """Returns a list of Log IDs of logs operated by operator_id.""" + log_ids = [] + for log in logs: + # operated_by is a list, in practice we have not witnessed + # a log co-operated by more than one operator. Ensure we take this + # case into consideration if it ever happens. + assert(len(log["operated_by"]) == 1) + if operator_id == log["operated_by"][0]: + log_key = base64.decodestring(log["key"]) + log_ids.append(hashlib.sha256(log_key).digest()) + return log_ids + + +def _is_log_disqualified(log): + return log.get("disqualified_at") != None + + +def _escape_c_string(s): + def _escape_char(c): + if 32 <= ord(c) <= 126 and c not in '\\"': + return c + else: + return '\\%03o' % ord(c) + return ''.join([_escape_char(c) for c in s]) + + +def _to_loginfo_struct(log): + """Converts the given log to a CTLogInfo initialization code.""" + log_key = base64.decodestring(log["key"]) + split_hex_key = _split_and_hexify_binary_data(log_key) + s = " {" + s += "\n ".join(split_hex_key) + s += ',\n %d' % (len(log_key)) + s += ',\n "%s"' % (_escape_c_string(log["description"])) + s += ',\n "https://%s"' % (log["url"]) + s += ',\n "%s"' % (log["dns_api_endpoint"]) + s += '}' + return s + + +def _get_log_definitions(logs): + """Returns a list of strings, each is a CTLogInfo definition.""" + list_code = [] + for log in logs: + list_code.append(_to_loginfo_struct(log)) + return list_code + + +def _to_disqualified_loginfo_struct(log): + log_key = base64.decodestring(log["key"]) + log_id = hashlib.sha256(log_key).digest() + s = " {" + s += "\n ".join(_split_and_hexify_binary_data(log_id)) + s += ",\n" + s += _to_loginfo_struct(log) + s += ",\n" + s += ' base::TimeDelta::FromSeconds(%d)' % (log["disqualified_at"]) + s += '}' + return s + + +def _get_disqualified_log_definitions(logs): + """Returns a list of DisqualifiedCTLogInfo definitions.""" + list_code = [] + for log in logs: + list_code.append(_to_disqualified_loginfo_struct(log)) + return list_code + + +def _sorted_disqualified_logs(all_logs): + return sorted( + filter(_is_log_disqualified, all_logs), + key=lambda l: hashlib.sha256( + base64.decodestring(l["key"])).digest()) + + +def _write_qualifying_logs_loginfo(f, qualifying_logs): + f.write("// The set of all presently-qualifying CT logs.\n" + "// Google provides DNS frontends for all of the logs.\n") + f.write("const CTLogInfo kCTLogList[] = {\n") + f.write(",\n".join(_get_log_definitions(qualifying_logs))) + f.write("\n};\n\n") + + +def generate_cpp_file(input_file, f): + """Generate a header file of known logs to be included by Chromium.""" + json_log_list = json.load(input_file) + _write_cpp_header(f) + + logs = json_log_list["logs"] + + # Write the list of currently-qualifying logs. + qualifying_logs = [log for log in logs if not _is_log_disqualified(log)] + _write_log_info_struct_definition(f) + _write_qualifying_logs_loginfo(f, qualifying_logs) + + # Write the IDs of all CT Logs operated by Google + google_log_ids = _get_log_ids_for_operator( + logs, _find_google_operator_id(json_log_list)) + f.writelines(_get_log_ids_array(google_log_ids, 'kGoogleLogIDs')) + + # Write the list of all disqualified logs. + _write_disqualified_log_info_struct_definition(f) + f.write("// The set of all disqualified logs, sorted by |log_id|.\n") + f.write("const DisqualifiedCTLogInfo kDisqualifiedCTLogList[] = {\n") + f.write(",\n".join( + _get_disqualified_log_definitions( + _sorted_disqualified_logs(logs)))) + f.write("\n};\n") + + +def main(): + if len(sys.argv) != 3: + print('usage: %s in_loglist_json out_header' % sys.argv[0]) + return 1 + with open(sys.argv[1], 'r') as infile, open(sys.argv[2], 'w') as outfile: + generate_cpp_file(infile, outfile) + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/net/tools/ct_log_list/make_ct_known_logs_list_unittest.py b/net/tools/ct_log_list/make_ct_known_logs_list_unittest.py new file mode 100755 index 0000000..804b3c2 --- /dev/null +++ b/net/tools/ct_log_list/make_ct_known_logs_list_unittest.py
@@ -0,0 +1,155 @@ +#!/usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import base64 +import hashlib +import sys +import unittest +import make_ct_known_logs_list + + +def b64e(x): + return base64.encodestring(x) + + +class FormattingTest(unittest.TestCase): + def testSplitAndHexifyBinData(self): + bin_data = ''.join([chr(i) for i in range(32,60)]) + expected_encoded_array = [ + ('"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a' + '\\x2b\\x2c\\x2d\\x2e\\x2f\\x30"'), + '"\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b"'] + self.assertEqual( + make_ct_known_logs_list._split_and_hexify_binary_data( + bin_data), + expected_encoded_array) + + # This data should fit in exactly one line - 17 bytes. + short_bin_data = ''.join([chr(i) for i in range(32, 49)]) + expected_short_array = [ + ('"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a' + '\\x2b\\x2c\\x2d\\x2e\\x2f\\x30"')] + self.assertEqual( + make_ct_known_logs_list._split_and_hexify_binary_data( + short_bin_data), + expected_short_array) + + # This data should fit exactly in two lines - 34 bytes. + two_line_data = ''.join([chr(i) for i in range(32, 66)]) + expected_two_line_data_array = [ + ('"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a' + '\\x2b\\x2c\\x2d\\x2e\\x2f\\x30"'), + ('"\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b' + '\\x3c\\x3d\\x3e\\x3f\\x40\\x41"')] + self.assertEqual( + make_ct_known_logs_list._split_and_hexify_binary_data( + short_bin_data), + expected_short_array) + + def testGetLogIDsArray(self): + log_ids = ["def", "abc", "ghi"] + expected_log_ids_code = [ + "// The list is sorted.\n", + "const char kTestIDs[][4] = {\n", + ' "\\x61\\x62\\x63",\n', + ' "\\x64\\x65\\x66",\n', + ' "\\x67\\x68\\x69"', + "};\n\n"] + self.assertEqual( + make_ct_known_logs_list._get_log_ids_array( + log_ids, "kTestIDs"), + expected_log_ids_code) + + def testToLogInfoStruct(self): + log = {"key": "YWJj", + "description": "Test Description", + "url": "ct.example.com", + "dns_api_endpoint": "dns.ct.example.com"} + expected_loginfo = ( + ' {"\\x61\\x62\\x63",\n 3,\n "Test Description",\n' + ' "https://ct.example.com",\n "dns.ct.example.com"}') + self.assertEqual( + make_ct_known_logs_list._to_loginfo_struct(log), + expected_loginfo) + + +class OperatorIDHandlingTest(unittest.TestCase): + def testFindingGoogleOperatorID(self): + ops_list = {"operators": [ + {"id": 0, "name": "First"}, + {"id": 1, "name": "Second"}]} + self.assertRaises( + RuntimeError, + make_ct_known_logs_list._find_google_operator_id, + ops_list) + ops_list["operators"].append({"id": 2, "name": "Google"}) + self.assertEqual( + make_ct_known_logs_list._find_google_operator_id(ops_list), + 2) + ops_list["operators"].append({"id": 3, "name": "Google"}) + self.assertRaises( + RuntimeError, + make_ct_known_logs_list._find_google_operator_id, + ops_list) + + def testCollectingLogIDsByOperator(self): + logs = [ + {"operated_by": (1,), "key": b64e('a')}, + {"operated_by": (2,), "key": b64e('b')}, + {"operated_by": (3,), "key": b64e('c')}, + {"operated_by": (1,), "key": b64e('d')} + ] + log_ids = make_ct_known_logs_list._get_log_ids_for_operator(logs, 1) + self.assertEqual(2, len(log_ids)) + self.assertItemsEqual( + [hashlib.sha256(t).digest() for t in ('a', 'd')], + log_ids) + + +class DisqualifiedLogsHandlingTest(unittest.TestCase): + def testCorrectlyIdentifiesDisqualifiedLog(self): + self.assertTrue( + make_ct_known_logs_list._is_log_disqualified( + {"disqualified_at" : 12345})) + self.assertFalse( + make_ct_known_logs_list._is_log_disqualified( + {"name" : "example"})) + + def testTranslatingToDisqualifiedLogDefinition(self): + log = {"key": "YWJj", + "description": "Test Description", + "url": "ct.example.com", + "dns_api_endpoint": "dns.ct.example.com", + "disqualified_at": 1464566400} + expected_disqualified_log_info = ( + ' {"\\xba\\x78\\x16\\xbf\\x8f\\x01\\xcf\\xea\\x41\\x41\\x40' + '\\xde\\x5d\\xae\\x22\\x23\\xb0"\n "\\x03\\x61\\xa3\\x96\\x17' + '\\x7a\\x9c\\xb4\\x10\\xff\\x61\\xf2\\x00\\x15\\xad",\n {"\\x61' + '\\x62\\x63",\n 3,\n "Test Description",\n ' + '"https://ct.example.com",\n "dns.ct.example.com"},\n ' + 'base::TimeDelta::FromSeconds(1464566400)}') + + self.assertEqual( + make_ct_known_logs_list._to_disqualified_loginfo_struct(log), + expected_disqualified_log_info) + + def testSortingAndFilteringDisqualifiedLogs(self): + logs = [ + {"disqualified_at": 1, "key": b64e('a')}, + {"key": b64e('b')}, + {"disqualified_at": 3, "key": b64e('c')}, + {"disqualified_at": 2, "key": b64e('d')}, + {"key": b64e('e')} + ] + disqualified_logs = make_ct_known_logs_list._sorted_disqualified_logs( + logs) + self.assertEqual(3, len(disqualified_logs)) + self.assertEqual(b64e('d'), disqualified_logs[0]["key"]) + self.assertEqual(b64e('c'), disqualified_logs[1]["key"]) + self.assertEqual(b64e('a'), disqualified_logs[2]["key"]) + + +if __name__ == '__main__': + unittest.main()
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc index a4727c7c..a320f485 100644 --- a/net/url_request/url_fetcher_core.cc +++ b/net/url_request/url_fetcher_core.cc
@@ -5,9 +5,12 @@ #include "net/url_request/url_fetcher_core.h" #include <stdint.h> +#include <algorithm> #include <utility> #include "base/bind.h" +#include "base/debug/alias.h" +#include "base/debug/dump_without_crashing.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/profiler/scoped_tracker.h" @@ -106,13 +109,24 @@ current_upload_bytes_(-1), current_response_bytes_(0), total_response_bytes_(-1), - traffic_annotation_(traffic_annotation) { + traffic_annotation_(traffic_annotation), + stack_identifier_(nullptr) { CHECK(original_url_.is_valid()); } void URLFetcherCore::Start() { DCHECK(delegate_task_runner_); DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!"; + + size_t stack_size = 0u; + stack_trace_on_start_ = base::MakeUnique<base::debug::StackTrace>(); + const void* const* addresses = stack_trace_on_start_->Addresses(&stack_size); + // The #5 frame is the frame of the consumer. #0 and #1 are the constructor + // for StackTrace(). #2 is for MakeUnique. #3 is for URLFetcherCore::Start(). + // #4 is URLFetcherImpl::Start(). + if (stack_size > 5 && addresses) + stack_identifier_ = addresses[5]; + if (network_task_runner_.get()) { DCHECK_EQ(network_task_runner_, request_context_getter_->GetNetworkTaskRunner()); @@ -556,6 +570,12 @@ request_context_getter_->AddObserver(this); request_ = request_context_getter_->GetURLRequestContext()->CreateRequest( original_url_, DEFAULT_PRIORITY, this, traffic_annotation_); + + // TODO(xunjieli): Temporary to investigate crbug.com/711721. + if (!request_context_getter_->GetURLRequestContext()->AddToAddressMap( + stack_identifier_)) { + DumpWithoutCrashing(); + } int flags = request_->load_flags() | load_flags_; // TODO(mmenke): This should really be with the other code to set the upload @@ -820,6 +840,9 @@ void URLFetcherCore::ReleaseRequest() { request_context_getter_->RemoveObserver(this); upload_progress_checker_timer_.reset(); + if (request_) + request_->context()->RemoveFromAddressMap(stack_identifier_); + request_.reset(); buffer_ = nullptr; g_registry.Get().RemoveURLFetcherCore(this); @@ -964,4 +987,24 @@ DCHECK(upload_stream_factory_.is_null()); } +void URLFetcherCore::DumpWithoutCrashing() const { + DCHECK(stack_trace_on_start_); + + size_t stack_size = 0u; + const void* const* instruction_pointers = + stack_trace_on_start_->Addresses(&stack_size); + static constexpr size_t kMaxStackSize = 100; + const void* instruction_pointers_copy[kMaxStackSize + 2]; + // Insert markers bracketing the crash to make it easier to locate. + memset(&instruction_pointers_copy[0], 0xAB, + sizeof(instruction_pointers_copy[0])); + memset(instruction_pointers_copy, 0xAB, sizeof(instruction_pointers_copy)); + stack_size = std::min(kMaxStackSize, stack_size); + std::memcpy(&instruction_pointers_copy[1], instruction_pointers, + stack_size * sizeof(const void*)); + base::debug::Alias(&stack_size); + base::debug::Alias(&instruction_pointers_copy); + base::debug::DumpWithoutCrashing(); +} + } // namespace net
diff --git a/net/url_request/url_fetcher_core.h b/net/url_request/url_fetcher_core.h index 53bcf62..503bbb40 100644 --- a/net/url_request/url_fetcher_core.h +++ b/net/url_request/url_fetcher_core.h
@@ -12,6 +12,7 @@ #include <string> #include "base/compiler_specific.h" +#include "base/debug/stack_trace.h" #include "base/files/file_path.h" #include "base/lazy_instance.h" #include "base/macros.h" @@ -230,6 +231,10 @@ // Check if any upload data is set or not. void AssertHasNoUploadData() const; + // Calls base::debug::DumpWithoutCrashing(). + // TODO(xunjieli): Temporary to investigate crbug.com/711721. + void DumpWithoutCrashing() const; + URLFetcher* fetcher_; // Corresponding fetcher object GURL original_url_; // The URL we were asked to fetch GURL url_; // The URL we eventually wound up at @@ -350,6 +355,10 @@ const net::NetworkTrafficAnnotationTag traffic_annotation_; + // TODO(xunjieli): Temporary to investigate crbug.com/711721. + std::unique_ptr<base::debug::StackTrace> stack_trace_on_start_; + void const* stack_identifier_; + static base::LazyInstance<Registry>::DestructorAtExit g_registry; DISALLOW_COPY_AND_ASSIGN(URLFetcherCore);
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc index c7e4477..b1f2988f 100644 --- a/net/url_request/url_request_context.cc +++ b/net/url_request/url_request_context.cc
@@ -5,6 +5,7 @@ #include "net/url_request/url_request_context.h" #include <inttypes.h> +#include <utility> #include "base/compiler_specific.h" #include "base/debug/alias.h" @@ -52,7 +53,8 @@ enable_brotli_(false), check_cleartext_permitted_(false), name_(nullptr), - largest_outstanding_requests_count_seen_(0) { + largest_outstanding_requests_count_seen_(0), + has_reported_too_many_outstanding_requests_(false) { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "URLRequestContext", base::ThreadTaskRunnerHandle::Get()); } @@ -123,6 +125,23 @@ cookie_store_ = cookie_store; } +bool URLRequestContext::AddToAddressMap(const void* const address) { + int count = ++address_map_[address]; + if (!has_reported_too_many_outstanding_requests_ && count > 1000) { + has_reported_too_many_outstanding_requests_ = true; + return false; + } + return true; +} + +void URLRequestContext::RemoveFromAddressMap(const void* const address) const { + auto iter = address_map_.find(address); + DCHECK(address_map_.end() != iter); + iter->second -= 1; + if (iter->second == 0) + address_map_.erase(iter); +} + void URLRequestContext::InsertURLRequest(const URLRequest* request) const { url_requests_.insert(request); if (url_requests_.size() > largest_outstanding_requests_count_seen_) { @@ -152,6 +171,7 @@ CHECK(false) << "Leaked " << num_requests << " URLRequest(s). First URL: " << request->url().spec().c_str() << "."; } + DCHECK(address_map_.empty()); } bool URLRequestContext::OnMemoryDump(
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 206b0105..96025de 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h
@@ -8,6 +8,7 @@ #ifndef NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_ #define NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_ +#include <map> #include <memory> #include <set> #include <string> @@ -225,6 +226,15 @@ return url_requests_; } + // TODO(xunjieli): Temporary to investigate crbug.com/711721. + + // Adds |address| to |address_map_|. Return false if the same address has been + // added for more than 1000 times but is not yet removed from the map. + bool AddToAddressMap(const void* const address); + + // Removes |address| from |address_map_|. + void RemoveFromAddressMap(const void* const address) const; + void InsertURLRequest(const URLRequest* request) const; void RemoveURLRequest(const URLRequest* request) const; @@ -333,6 +343,16 @@ // |this| and are not yet destroyed. This doesn't need to be in CopyFrom. mutable size_t largest_outstanding_requests_count_seen_; + // TODO(xunjieli): Remove after crbug.com/711721 is fixed. + + // A map of frame address to the number of outstanding requests that are + // associated with that address. + mutable std::map<const void* const, int> address_map_; + + // Whether AddToAddressMap() has reported false. This is to avoid gathering + // too many crash dumps when users run into this scenario. + bool has_reported_too_many_outstanding_requests_; + DISALLOW_COPY_AND_ASSIGN(URLRequestContext); };
diff --git a/net/url_request/url_request_context_unittest.cc b/net/url_request/url_request_context_unittest.cc index 147e350..1597a39 100644 --- a/net/url_request/url_request_context_unittest.cc +++ b/net/url_request/url_request_context_unittest.cc
@@ -5,16 +5,40 @@ #include "net/url_request/url_request_context.h" #include <memory> +#include <utility> +#include <vector> #include "base/memory/ptr_util.h" +#include "base/test/histogram_tester.h" #include "base/trace_event/memory_dump_request_args.h" #include "base/trace_event/process_memory_dump.h" #include "net/proxy/proxy_config_service_fixed.h" +#include "net/test/url_request/url_request_failed_job.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_context_builder.h" +#include "net/url_request/url_request_filter.h" +#include "net/url_request/url_request_interceptor.h" +#include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { +namespace { + +class HangingRequestInterceptor : public URLRequestInterceptor { + public: + HangingRequestInterceptor() {} + ~HangingRequestInterceptor() override {} + + URLRequestJob* MaybeInterceptRequest( + URLRequest* request, + NetworkDelegate* network_delegate) const override { + return new URLRequestFailedJob(request, network_delegate, ERR_IO_PENDING); + } +}; + +} // namespace + class URLRequestContextMemoryDumpTest : public testing::TestWithParam< base::trace_event::MemoryDumpLevelOfDetail> {}; @@ -66,4 +90,37 @@ } // TODO(xunjieli): Add more granular tests on the MemoryDumpProvider. + +// Tests that if many requests are outstanding, histogram is reported correctly. +TEST(URLRequestContextTest, TooManyRequests) { + TestURLRequestContext context(false); + base::HistogramTester histogram_tester; + std::unique_ptr<URLRequestInterceptor> interceptor( + new HangingRequestInterceptor()); + GURL url("http://www.example.com"); + URLRequestFilter::GetInstance()->AddUrlInterceptor(url, + std::move(interceptor)); + std::vector<std::unique_ptr<URLRequest>> outstanding_requests; + const int kNumRequestLimit = 1000; + // Make two more requests above the limit to test that AddToAddressMap() only + // returns false once. + const int kNumRequests = kNumRequestLimit + 2; + const void* const dummy_address = &context; + for (int i = 0; i < kNumRequests; ++i) { + TestDelegate test_delegate; + test_delegate.set_quit_on_complete(true); + std::unique_ptr<URLRequest> request = context.CreateRequest( + url, DEFAULT_PRIORITY, &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(i != kNumRequestLimit, context.AddToAddressMap(dummy_address)); + request->Start(); + outstanding_requests.push_back(std::move(request)); + } + + histogram_tester.ExpectTotalCount("Net.URLRequestContext.OutstandingRequests", + kNumRequests); + for (int i = 0; i < kNumRequests; ++i) { + context.RemoveFromAddressMap(dummy_address); + } +} + } // namespace net
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index dc5c4935..d87b126 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -10964,65 +10964,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build155-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build155-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -17507,65 +17448,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build219-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build219-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index c03d7070..d4161ba 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -10951,65 +10951,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build149-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build149-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -17514,65 +17455,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build103-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build103-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -24037,65 +23919,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build159-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build159-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -30560,65 +30383,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build124-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build124-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -37083,65 +36847,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build25-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build25-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -43606,65 +43311,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build129-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build129-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -50129,65 +49775,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build5-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build5-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -56652,65 +56239,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build118-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build118-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -63195,65 +62723,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build133-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build133-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -69798,65 +69267,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build102-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build102-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -76381,65 +75791,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build165-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build165-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -82984,65 +82335,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build93-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build93-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -89567,65 +88859,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build186-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build186-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -96130,65 +95363,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build139-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build139-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -102713,65 +101887,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build144-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build144-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results", @@ -109236,65 +108351,6 @@ }, { "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build31-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "spaceport", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "spaceport.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build31-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "speedometer", "-v", "--upload-results",
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/window-open-invalid-url.html b/third_party/WebKit/LayoutTests/fast/dom/Window/window-open-invalid-url.html new file mode 100644 index 0000000..2b03ed6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/Window/window-open-invalid-url.html
@@ -0,0 +1,9 @@ +<!doctype html> +<title>window.open: invalid URL</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script> + test(() => { + assert_throws("SyntaxError", () => { self.open("http:"); }); + }, "Check that window.open() throws on an invalid URL."); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/payments/payment-instruments.html b/third_party/WebKit/LayoutTests/http/tests/payments/payment-instruments.html index 8b2c06bf..1e01ca6b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/payments/payment-instruments.html +++ b/third_party/WebKit/LayoutTests/http/tests/payments/payment-instruments.html
@@ -161,4 +161,54 @@ .catch(unreached_rejection(test)); }, 'PaymentInstruments |keys| method test'); +promise_test(test => { + var registration; + var script_url = 'resources/empty-worker.js'; + var scope = 'resources/'; + + return service_worker_unregister_and_register(test, script_url, scope) + .then(r => { + registration = r; + return wait_for_state(test, registration.installing, 'activated'); + }) + .then(state => { + assert_equals(state, 'activated'); + var instruments = [ + registration.paymentManager.instruments.set( + 'test_key1', + { + name: 'Visa ending ****4756', + enabledMethods: ['basic-card'], + capabilities: { + supportedNetworks: ['visa'], + supportedTypes: ['credit'] + } + }), + registration.paymentManager.instruments.set( + 'test_key2', + { + name: "My Bob Pay Account: john@example.com", + enabledMethods: ["https://bobpay.com/"] + }) + ]; + return Promise.all(instruments); + }) + .then(result => { + assert_array_equals(result, [undefined, undefined]); + return registration.paymentManager.instruments.keys(); + }) + .then(result => { + assert_equals(result.length, 2); + return registration.paymentManager.instruments.clear(); + }) + .then(result => { + assert_equals(result, undefined); + return registration.paymentManager.instruments.keys(); + }) + .then(result => { + assert_equals(result.length, 0); + }) + .catch(unreached_rejection(test)); + }, 'PaymentInstruments |clear| method test'); + </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 58596a0..6af047d 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -760,6 +760,7 @@ method quadraticCurveTo method rect interface PaymentInstruments + method clear method constructor method delete method get
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index ff02c2e..918d5d1 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -753,6 +753,7 @@ method quadraticCurveTo method rect interface PaymentInstruments + method clear method constructor method delete method get
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 58596a0..6af047d 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -760,6 +760,7 @@ method quadraticCurveTo method rect interface PaymentInstruments + method clear method constructor method delete method get
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp index 62343eb2..a5ebd0fb 100644 --- a/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8WindowCustom.cpp
@@ -287,7 +287,11 @@ // passed the BindingSecurity check above. DOMWindow* opened_window = ToLocalDOMWindow(impl)->open( url_string, frame_name, window_features_string, - CurrentDOMWindow(info.GetIsolate()), EnteredDOMWindow(info.GetIsolate())); + CurrentDOMWindow(info.GetIsolate()), EnteredDOMWindow(info.GetIsolate()), + exception_state); + if (exception_state.HadException()) { + return; + } if (!opened_window) { V8SetReturnValueNull(info); return;
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp index 61cf04db..80de18a 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -1610,7 +1610,8 @@ const AtomicString& frame_name, const String& window_features_string, LocalDOMWindow* calling_window, - LocalDOMWindow* entered_window) { + LocalDOMWindow* entered_window, + ExceptionState& exception_state) { if (!IsCurrentlyDisplayedInFrame()) return nullptr; if (!calling_window->GetFrame()) @@ -1668,7 +1669,7 @@ WindowFeatures features(window_features_string); DOMWindow* new_window = CreateWindow(url_string, frame_name, features, *calling_window, - *first_frame, *GetFrame()); + *first_frame, *GetFrame(), exception_state); return features.noopener ? nullptr : new_window; }
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h index c4d4275..4f779245 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
@@ -54,6 +54,7 @@ class DOMWindowEventQueue; class Element; class EventQueue; +class ExceptionState; class External; class FrameConsole; class FrameRequestCallback; @@ -272,7 +273,8 @@ const AtomicString& frame_name, const String& window_features_string, LocalDOMWindow* calling_window, - LocalDOMWindow* entered_window); + LocalDOMWindow* entered_window, + ExceptionState&); FrameConsole* GetFrameConsole() const;
diff --git a/third_party/WebKit/Source/core/frame/Window.idl b/third_party/WebKit/Source/core/frame/Window.idl index 2bbfaa86..015c9b4 100644 --- a/third_party/WebKit/Source/core/frame/Window.idl +++ b/third_party/WebKit/Source/core/frame/Window.idl
@@ -63,7 +63,7 @@ [Replaceable, CrossOrigin] readonly attribute Window? parent; [CheckSecurity=ReturnValue, Custom=Getter] readonly attribute Element? frameElement; // FIXME: open() should have 4 optional arguments with defaults. - [Custom] Window? open(DOMString url, DOMString target, optional DOMString features); + [Custom, RaisesException] Window? open(DOMString url, DOMString target, optional DOMString features); // indexed properties // https://html.spec.whatwg.org/C/browsers.html#windowproxy-getownproperty
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.cpp b/third_party/WebKit/Source/core/page/CreateWindow.cpp index afa0cff..9f51a0f 100644 --- a/third_party/WebKit/Source/core/page/CreateWindow.cpp +++ b/third_party/WebKit/Source/core/page/CreateWindow.cpp
@@ -26,6 +26,7 @@ #include "core/page/CreateWindow.h" +#include "bindings/core/v8/ExceptionState.h" #include "core/dom/Document.h" #include "core/frame/FrameClient.h" #include "core/frame/LocalFrame.h" @@ -179,7 +180,8 @@ const WindowFeatures& window_features, LocalDOMWindow& calling_window, LocalFrame& first_frame, - LocalFrame& opener_frame) { + LocalFrame& opener_frame, + ExceptionState& exception_state) { LocalFrame* active_frame = calling_window.GetFrame(); ASSERT(active_frame); @@ -188,10 +190,9 @@ : first_frame.GetDocument()->CompleteURL(url_string); if (!completed_url.IsEmpty() && !completed_url.IsValid()) { UseCounter::Count(active_frame, UseCounter::kWindowOpenWithInvalidURL); - // Don't expose client code to invalid URLs. - calling_window.PrintErrorMessage( - "Unable to open a window with invalid URL '" + - completed_url.GetString() + "'.\n"); + exception_state.ThrowDOMException( + kSyntaxError, "Unable to open a window with invalid URL '" + + completed_url.GetString() + "'.\n"); return nullptr; }
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.h b/third_party/WebKit/Source/core/page/CreateWindow.h index 2a69d23..ee4d3cc 100644 --- a/third_party/WebKit/Source/core/page/CreateWindow.h +++ b/third_party/WebKit/Source/core/page/CreateWindow.h
@@ -36,6 +36,7 @@ #undef CreateWindow namespace blink { +class ExceptionState; class LocalFrame; struct FrameLoadRequest; struct WindowFeatures; @@ -45,7 +46,8 @@ const WindowFeatures&, LocalDOMWindow& calling_window, LocalFrame& first_frame, - LocalFrame& opener_frame); + LocalFrame& opener_frame, + ExceptionState&); void CreateWindowForRequest(const FrameLoadRequest&, LocalFrame& opener_frame,
diff --git a/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp b/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp index 746145f..8905048b 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp
@@ -165,6 +165,22 @@ return promise; } +ScriptPromise PaymentInstruments::clear(ScriptState* script_state) { + if (!manager_.is_bound()) { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create(kInvalidStateError, kPaymentManagerUnavailable)); + } + + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise promise = resolver->Promise(); + + manager_->ClearPaymentInstruments(ConvertToBaseCallback( + WTF::Bind(&PaymentInstruments::onClearPaymentInstruments, + WrapPersistent(this), WrapPersistent(resolver)))); + return promise; +} + DEFINE_TRACE(PaymentInstruments) {} void PaymentInstruments::onDeletePaymentInstrument( @@ -235,4 +251,13 @@ resolver->Resolve(); } +void PaymentInstruments::onClearPaymentInstruments( + ScriptPromiseResolver* resolver, + payments::mojom::blink::PaymentHandlerStatus status) { + DCHECK(resolver); + if (rejectError(resolver, status)) + return; + resolver->Resolve(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/PaymentInstruments.h b/third_party/WebKit/Source/modules/payments/PaymentInstruments.h index 689c541..993d474 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentInstruments.h +++ b/third_party/WebKit/Source/modules/payments/PaymentInstruments.h
@@ -37,6 +37,7 @@ const String& instrument_key, const PaymentInstrument& details, ExceptionState&); + ScriptPromise clear(ScriptState*); DECLARE_TRACE(); @@ -53,6 +54,8 @@ payments::mojom::blink::PaymentHandlerStatus); void onSetPaymentInstrument(ScriptPromiseResolver*, payments::mojom::blink::PaymentHandlerStatus); + void onClearPaymentInstruments(ScriptPromiseResolver*, + payments::mojom::blink::PaymentHandlerStatus); const payments::mojom::blink::PaymentManagerPtr& manager_; };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentInstruments.idl b/third_party/WebKit/Source/modules/payments/PaymentInstruments.idl index 2079ab6..1586755 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentInstruments.idl +++ b/third_party/WebKit/Source/modules/payments/PaymentInstruments.idl
@@ -13,4 +13,5 @@ [CallWith=ScriptState] Promise<sequence<DOMString>> keys(); [CallWith=ScriptState] Promise<boolean> has(DOMString instrumentKey); [CallWith=ScriptState, RaisesException] Promise<void> set(DOMString instrumentKey, PaymentInstrument details); + [CallWith=ScriptState] Promise<void> clear(); };
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc index f3369ecb..1dd4c106 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -470,6 +470,27 @@ } } +void RendererSchedulerImpl::BeginMainFrameNotExpectedUntil( + base::TimeTicks time) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::BeginMainFrametime"); + helper_.CheckOnValidThread(); + if (helper_.IsShutdown()) + return; + + base::TimeTicks now(helper_.scheduler_tqm_delegate()->NowTicks()); + + if (now < time) { + // End any previous idle period. + EndIdlePeriod(); + + // TODO(rmcilroy): Consider reducing the idle period based on the runtime of + // the next pending delayed tasks (as currently done in for long idle times) + idle_helper_.StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, time); + } +} + void RendererSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererSchedulerImpl::SetAllRenderWidgetsHidden", "hidden",
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h index a9c0be3..01ac87f 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -90,6 +90,7 @@ override; void WillBeginFrame(const cc::BeginFrameArgs& args) override; void BeginFrameNotExpectedSoon() override; + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void DidCommitFrameToCompositor() override; void DidHandleInputEventOnCompositorThread( const WebInputEvent& web_input_event,
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc index f2f6239d..2cc3b00 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -2065,6 +2065,28 @@ std::string("3"))); } +TEST_F(RendererSchedulerImplTest, TestBeginMainFrameNotExpectedUntil) { + base::TimeDelta ten_millis(base::TimeDelta::FromMilliseconds(10)); + base::TimeTicks expected_deadline = clock_->NowTicks() + ten_millis; + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period. + + base::TimeTicks now = clock_->NowTicks(); + base::TimeTicks frame_time = now + ten_millis; + // No main frame is expected until frame_time, so short idle work can be + // scheduled in the mean time. + scheduler_->BeginMainFrameNotExpectedUntil(frame_time); + RunUntilIdle(); + EXPECT_EQ(1, run_count); // Should have run in a long idle time. + EXPECT_EQ(expected_deadline, deadline_in_task); +} + TEST_F(RendererSchedulerImplTest, TestLongIdlePeriod) { base::TimeTicks expected_deadline = clock_->NowTicks() + maximum_idle_period_duration();
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc index c65d915..78f7640 100644 --- a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc +++ b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
@@ -51,6 +51,9 @@ void FakeRendererScheduler::BeginFrameNotExpectedSoon() {} +void FakeRendererScheduler::BeginMainFrameNotExpectedUntil( + base::TimeTicks time) {} + void FakeRendererScheduler::DidCommitFrameToCompositor() {} void FakeRendererScheduler::DidHandleInputEventOnCompositorThread(
diff --git a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h index d543a05..b1a52888 100644 --- a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h +++ b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
@@ -78,6 +78,7 @@ void DidBeginMainFrame() override {} void BeginMainFrame(const cc::BeginFrameArgs& args) override {} void BeginMainFrameNotExpectedSoon() override {} + void BeginMainFrameNotExpectedUntil(base::TimeTicks) override {} void UpdateLayerTreeHost() override; void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, const gfx::Vector2dF& outer_delta,
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index 5235674..10f003dd 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -9450,15 +9450,16 @@ ToWebLocalFrameImpl(MainFrame())->GetFrame()->DomWindow(); KURL destination = ToKURL("data:text/html:destination"); + NonThrowableExceptionState exception_state; main_window->open(destination.GetString(), "frame1", "", main_window, - main_window); + main_window, exception_state); ASSERT_FALSE(remote_client.LastRequest().IsNull()); EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(destination)); // Pointing a named frame to an empty URL should just return a reference to // the frame's window without navigating it. - DOMWindow* result = - main_window->open("", "frame1", "", main_window, main_window); + DOMWindow* result = main_window->open("", "frame1", "", main_window, + main_window, exception_state); EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(destination)); EXPECT_EQ(result, WebFrame::ToCoreFrame(*remote_frame)->DomWindow());
diff --git a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h index 0f0a7d8..090f940 100644 --- a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h
@@ -72,6 +72,12 @@ // need to be drawn. Must be called from the main thread. virtual void BeginFrameNotExpectedSoon() = 0; + // Called to notify about the start of a period where main frames are not + // scheduled and so short idle work can be scheduled. This will precede + // BeginFrameNotExpectedSoon and is also called when the compositor may be + // busy but the main thread is not. + virtual void BeginMainFrameNotExpectedUntil(base::TimeTicks time) = 0; + // Called to notify about the start of a new frame. Must be called from the // main thread. virtual void WillBeginFrame(const cc::BeginFrameArgs& args) = 0;
diff --git a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h index 4bcc9d80..c828f19 100644 --- a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h
@@ -27,6 +27,7 @@ override; void WillBeginFrame(const cc::BeginFrameArgs& args) override; void BeginFrameNotExpectedSoon() override; + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void DidCommitFrameToCompositor() override; void DidHandleInputEventOnCompositorThread( const WebInputEvent& web_input_event,
diff --git a/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h index 7cea5445..839747f0 100644 --- a/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h
@@ -33,6 +33,7 @@ std::unique_ptr<RenderWidgetSchedulingState>()); MOCK_METHOD1(WillBeginFrame, void(const cc::BeginFrameArgs&)); MOCK_METHOD0(BeginFrameNotExpectedSoon, void()); + MOCK_METHOD1(BeginMainFrameNotExpectedUntil, void(base::TimeTicks)); MOCK_METHOD0(DidCommitFrameToCompositor, void()); MOCK_METHOD2(DidHandleInputEventOnCompositorThread, void(const WebInputEvent&, InputEventState));
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py index 5ba591a..399ccea 100755 --- a/tools/gn/bootstrap/bootstrap.py +++ b/tools/gn/bootstrap/bootstrap.py
@@ -546,6 +546,7 @@ 'base/trace_event/memory_infra_background_whitelist.cc', 'base/trace_event/memory_peak_detector.cc', 'base/trace_event/memory_tracing_observer.cc', + 'base/trace_event/memory_usage_estimator.cc', 'base/trace_event/process_memory_dump.cc', 'base/trace_event/process_memory_maps.cc', 'base/trace_event/process_memory_totals.cc',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index acef7c5..9327772 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -21849,6 +21849,7 @@ <int value="1067618884" label="enable-experimental-input-view-features"/> <int value="1070164693" label="MidiManagerDynamicInstantiation:disabled"/> <int value="1070300488" label="disable-webgl"/> + <int value="1074359194" label="UseSuggestionsEvenIfFew:enabled"/> <int value="1081546525" label="ash-enable-docked-windows"/> <int value="1087235172" label="file-manager-enable-new-audio-player"/> <int value="1090377940" label="enable-quic-https"/> @@ -22069,6 +22070,7 @@ <int value="1865799183" label="javascript-harmony"/> <int value="1866079109" label="team-drives"/> <int value="1867085340" label="brotli-encoding:enabled"/> + <int value="1874604540" label="UseSuggestionsEvenIfFew:disabled"/> <int value="1878331098" label="GuestViewCrossProcessFrames:enabled"/> <int value="1881036528" label="disable-multilingual-spellchecker"/> <int value="1881174782" label="disable-brotli"/>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 1add5e47..d0797fc 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -121,7 +121,6 @@ smoothness.tough_texture_upload_cases,vmiura@chromium.org, smoothness.tough_webgl_ad_cases,skyostil@chromium.org, smoothness.tough_webgl_cases,"kbr@chromium.org, zmo@chromium.org", -spaceport,junov@chromium.org, speedometer,"bmeurer@chromium.org, mvstanton@chromium.org", speedometer-classic,hablich@chromium.org, speedometer-turbo,hablich@chromium.org,
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py index b386869..b910e706 100644 --- a/tools/perf/benchmarks/benchmark_smoke_unittest.py +++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -28,7 +28,6 @@ from benchmarks import octane from benchmarks import rasterize_and_record_micro from benchmarks import repaint -from benchmarks import spaceport from benchmarks import speedometer from benchmarks import text_selection from benchmarks import v8_browsing @@ -96,7 +95,6 @@ octane, # Often fails & take long time to timeout on cq bot. rasterize_and_record_micro, # Always fails on cq bot. repaint, # Often fails & takes long time to timeout on cq bot. - spaceport, # Takes 451 seconds. speedometer, # Takes 101 seconds. jetstream, # Take 206 seconds. text_selection, # Always fails on cq bot.
diff --git a/tools/perf/benchmarks/spaceport.py b/tools/perf/benchmarks/spaceport.py deleted file mode 100644 index cd80b078..0000000 --- a/tools/perf/benchmarks/spaceport.py +++ /dev/null
@@ -1,128 +0,0 @@ -# Copyright 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Runs spaceport.io's PerfMarks benchmark.""" - -import json -import logging -import os - -from core import path_util -from core import perf_benchmark - -from telemetry import benchmark -from telemetry import page as page_module -from telemetry.page import legacy_page_test -from telemetry import story -from telemetry.value import list_of_scalar_values -from telemetry.value import scalar - -DESCRIPTIONS = { - 'canvasDrawImageFullClear': - 'Using a canvas element to render. Bitmaps are blitted to the canvas ' - 'using the "drawImage" function and the canvas is fully cleared at ' - 'the beginning of each frame.', - 'canvasDrawImageFullClearAlign': - 'Same as canvasDrawImageFullClear except all "x" and "y" values are ' - 'rounded to the nearest integer. This can be more efficient on ' - 'translate on certain browsers.', - 'canvasDrawImagePartialClear': - 'Using a canvas element to render. Bitmaps are blitted to the canvas ' - 'using the "drawImage" function and pixels drawn in the last frame ' - 'are cleared to the clear color at the beginning of each frame. ' - 'This is generally slower on hardware accelerated implementations, ' - 'but sometimes faster on CPU-based implementations.', - 'canvasDrawImagePartialClearAlign': - 'Same as canvasDrawImageFullClearAlign but only partially clearing ' - 'the canvas each frame.', - 'css2dBackground': - 'Using div elements that have a background image specified using CSS ' - 'styles. These div elements are translated, scaled, and rotated using ' - 'CSS-2D transforms.', - 'css2dImg': - 'Same as css2dBackground, but using img elements instead of div ' - 'elements.', - 'css3dBackground': - 'Same as css2dBackground, but using CSS-3D transforms.', - 'css3dImg': - 'Same as css2dImage but using CSS-3D tranforms.', -} - - -class _SpaceportMeasurement(legacy_page_test.LegacyPageTest): - - def __init__(self): - super(_SpaceportMeasurement, self).__init__() - - def CustomizeBrowserOptions(self, options): - options.AppendExtraBrowserArgs('--disable-gpu-vsync') - - def ValidateAndMeasurePage(self, page, tab, results): - del page # unused - tab.WaitForJavaScriptCondition( - '!document.getElementById("start-performance-tests").disabled', - timeout=60) - - tab.ExecuteJavaScript(""" - window.__results = {}; - window.console.log = function(str) { - if (!str) return; - var key_val = str.split(': '); - if (!key_val.length == 2) return; - __results[key_val[0]] = key_val[1]; - }; - document.getElementById('start-performance-tests').click(); - """) - - num_results = 0 - num_tests_in_spaceport = 24 - while num_results < num_tests_in_spaceport: - tab.WaitForJavaScriptCondition( - 'Object.keys(window.__results).length > {{ num_results }}', - num_results=num_results, - timeout=180) - num_results = tab.EvaluateJavaScript( - 'Object.keys(window.__results).length') - logging.info('Completed test %d of %d', - num_results, num_tests_in_spaceport) - - result_dict = json.loads(tab.EvaluateJavaScript( - 'JSON.stringify(window.__results)')) - for key in result_dict: - chart, trace = key.split('.', 1) - results.AddValue(scalar.ScalarValue( - results.current_page, '%s.%s' % (chart, trace), - 'objects (bigger is better)', float(result_dict[key]), - important=False, description=DESCRIPTIONS.get(chart))) - results.AddValue(list_of_scalar_values.ListOfScalarValues( - results.current_page, 'Score', 'objects (bigger is better)', - [float(x) for x in result_dict.values()], - description='Combined score for all parts of the spaceport benchmark.')) - - -# crbug.com/166703: This test frequently times out on Windows. -@benchmark.Disabled('mac', 'win', - 'linux', 'android') # crbug.com/525112 -@benchmark.Owner(emails=['junov@chromium.org']) -class Spaceport(perf_benchmark.PerfBenchmark): - """spaceport.io's PerfMarks benchmark. - - http://spaceport.io/community/perfmarks - - This test performs 3 animations (rotate, translate, scale) using a variety of - methods (css, webgl, canvas, etc) and reports the number of objects that can - be simultaneously animated while still achieving 30FPS. - """ - test = _SpaceportMeasurement - - @classmethod - def Name(cls): - return 'spaceport' - - def CreateStorySet(self, options): - spaceport_dir = os.path.join(path_util.GetChromiumSrcDir(), 'chrome', - 'test', 'data', 'third_party', 'spaceport') - ps = story.StorySet(base_dir=spaceport_dir) - ps.AddStory(page_module.Page('file://index.html', ps, ps.base_dir)) - return ps
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 45357f61..5557dd70 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -482,6 +482,8 @@ void Compositor::BeginMainFrameNotExpectedSoon() { } +void Compositor::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {} + static void SendDamagedRectsRecursive(ui::Layer* layer) { layer->SendDamagedRects(); for (auto* child : layer->children())
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 2e95a3f..ce43299 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -326,6 +326,7 @@ void DidBeginMainFrame() override {} void BeginMainFrame(const cc::BeginFrameArgs& args) override; void BeginMainFrameNotExpectedSoon() override; + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void UpdateLayerTreeHost() override; void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, const gfx::Vector2dF& outer_delta,