diff --git a/DEPS b/DEPS index 249851f6..e0235356 100644 --- a/DEPS +++ b/DEPS
@@ -179,11 +179,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '6dee176c8d7d712a23d3841c26ff9e6738fdbe2b', + 'angle_revision': '7f418fc2677a978c77f1a3aba4b163b7501ed960', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'a68a80a4dbf9dc7fab42a2734c854a41d23136cc', + 'swiftshader_revision': '26c6c4a5eb838b67b2c8895406bb9fd07b69ac83', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -286,7 +286,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': 'e99b9182214fe7797803d89fa4d5f830d9a57bbb', + 'spv_tools_revision': '3cdd6444cf91a5d74007eb0685885f0512066c4d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -862,7 +862,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9fdb14b94056dfeeda68c3a9afbdece693ac9150', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b582d244f3160b24d6b2edadc680fc0f03b7194d', 'condition': 'checkout_linux', }, @@ -1280,7 +1280,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '45f9f6cebc3a5956cee84448fa90b499dc8a8bf4', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '87ede8895026c93bf0336f61d8cbb5954d42c19e', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1470,7 +1470,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '2701c130839edbeb226735b0775966b6423d9e83', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '7bf8699dd1ce209faaefa1c1176dc99c1252eef3', + Var('webrtc_git') + '/src.git' + '@' + '55d19e590d9a6ed6d8b3ad97b6ea62158e56705b', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1532,7 +1532,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@12fa2ef9c6d1da02a5c9e27974b428eca75a05c6', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1f4ca326d0db23bfe3e747bbc35f2c18adb4cffe', 'condition': 'checkout_src_internal', },
diff --git a/ash/magnifier/docked_magnifier_controller_impl.cc b/ash/magnifier/docked_magnifier_controller_impl.cc index cb5b7f7..68d0111 100644 --- a/ash/magnifier/docked_magnifier_controller_impl.cc +++ b/ash/magnifier/docked_magnifier_controller_impl.cc
@@ -312,6 +312,10 @@ viewport_magnifier_layer_->SetTransform(transform); } +int DockedMagnifierControllerImpl::GetMagnifierHeightForTesting() const { + return GetTotalMagnifierHeight(); +} + void DockedMagnifierControllerImpl::OnActiveUserPrefServiceChanged( PrefService* pref_service) { active_user_pref_service_ = pref_service;
diff --git a/ash/magnifier/docked_magnifier_controller_impl.h b/ash/magnifier/docked_magnifier_controller_impl.h index 119b202f..cd5a78e 100644 --- a/ash/magnifier/docked_magnifier_controller_impl.h +++ b/ash/magnifier/docked_magnifier_controller_impl.h
@@ -79,6 +79,7 @@ // DockedMagnifierController: void CenterOnPoint(const gfx::Point& point_in_screen) override; + int GetMagnifierHeightForTesting() const override; // ash::SessionObserver: void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
diff --git a/ash/public/cpp/docked_magnifier_controller.h b/ash/public/cpp/docked_magnifier_controller.h index 88f9583..d3ae84c 100644 --- a/ash/public/cpp/docked_magnifier_controller.h +++ b/ash/public/cpp/docked_magnifier_controller.h
@@ -26,6 +26,9 @@ // by itself. virtual void CenterOnPoint(const gfx::Point& point_in_screen) = 0; + // Returns docked magnifier height. + virtual int GetMagnifierHeightForTesting() const = 0; + protected: virtual ~DockedMagnifierController() = default; };
diff --git a/ash/shelf/shelf_application_menu_model.cc b/ash/shelf/shelf_application_menu_model.cc index 91902d7a4..7219335 100644 --- a/ash/shelf/shelf_application_menu_model.cc +++ b/ash/shelf/shelf_application_menu_model.cc
@@ -20,7 +20,7 @@ Items items, ShelfItemDelegate* delegate) : ui::SimpleMenuModel(this), delegate_(delegate) { - AddTitle(title); + AddItem(std::numeric_limits<int>::max(), title); for (size_t i = 0; i < items.size(); i++) AddItemWithIcon(i, items[i].first, items[i].second); AddSeparator(ui::SPACING_SEPARATOR);
diff --git a/ash/shelf/shelf_application_menu_model_unittest.cc b/ash/shelf/shelf_application_menu_model_unittest.cc index dc49e43..2436ce8 100644 --- a/ash/shelf/shelf_application_menu_model_unittest.cc +++ b/ash/shelf/shelf_application_menu_model_unittest.cc
@@ -51,7 +51,7 @@ ShelfApplicationMenuModel menu(title, {}, nullptr); // Expect the title and a separator. ASSERT_EQ(2, menu.GetItemCount()); - EXPECT_EQ(ui::MenuModel::TYPE_TITLE, menu.GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(0)); EXPECT_EQ(title, menu.GetLabelAt(0)); EXPECT_FALSE(menu.IsEnabledAt(0)); EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(1)); @@ -75,7 +75,7 @@ ASSERT_EQ(static_cast<int>(5), menu.GetItemCount()); // The label title should not be enabled. - EXPECT_EQ(ui::MenuModel::TYPE_TITLE, menu.GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(0)); EXPECT_EQ(title, menu.GetLabelAt(0)); EXPECT_FALSE(menu.IsEnabledAt(0));
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index d28e37f1..e6db5922 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -1698,7 +1698,7 @@ overflow_shelf_view->GetPreferredSize().width()); } -TEST_F(ShelfViewTest, OverflowShelfColorIsDerivedFromWallpaper) { +TEST_F(ShelfViewTest, DISABLED_OverflowShelfColorIsDerivedFromWallpaper) { // No overflow bubble when scrollable shelf enabled. // TODO(https://crbug.com/1002576): revisit when scrollable shelf is launched. if (chromeos::switches::ShouldShowScrollableShelf()) @@ -1905,7 +1905,7 @@ // Checks various drag and drop operations from OverflowBubble to Shelf, and // vice versa. -TEST_F(ShelfViewTest, CheckDragAndDropFromShelfToOtherShelf) { +TEST_F(ShelfViewTest, DISABLED_CheckDragAndDropFromShelfToOtherShelf) { // No overflow bubble when scrollable shelf enabled. // TODO(https://crbug.com/1002576): revisit when scrollable shelf is launched. if (chromeos::switches::ShouldShowScrollableShelf())
diff --git a/base/allocator/allocator_shim_default_dispatch_to_glibc.cc b/base/allocator/allocator_shim_default_dispatch_to_glibc.cc index aa19b7a..8915606 100644 --- a/base/allocator/allocator_shim_default_dispatch_to_glibc.cc +++ b/base/allocator/allocator_shim_default_dispatch_to_glibc.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/allocator/allocator_shim.h" +#include "base/memory/protected_memory_cfi.h" #include <dlfcn.h> #include <malloc.h> @@ -22,6 +23,10 @@ namespace { using base::allocator::AllocatorDispatch; +using MallocUsableSizeFunction = decltype(malloc_usable_size)*; + +PROTECTED_MEMORY_SECTION base::ProtectedMemory<MallocUsableSizeFunction> + g_MallocUsableSizeFunction; void* GlibcMalloc(const AllocatorDispatch*, size_t size, void* context) { return __libc_malloc(size); @@ -59,12 +64,11 @@ // resolve it instead. This should be safe because glibc (and hence dlfcn) // does not use malloc_size internally and so there should not be a risk of // recursion. - using MallocUsableSizeFunction = decltype(malloc_usable_size)*; - static MallocUsableSizeFunction fn_ptr = - reinterpret_cast<MallocUsableSizeFunction>( - dlsym(RTLD_NEXT, "malloc_usable_size")); + static base::ProtectedMemory<MallocUsableSizeFunction>::Initializer init( + &g_MallocUsableSizeFunction, reinterpret_cast<MallocUsableSizeFunction>( + dlsym(RTLD_NEXT, "malloc_usable_size"))); - return fn_ptr(address); + return base::UnsanitizedCfiCall(g_MallocUsableSizeFunction)(address); } } // namespace
diff --git a/base/bind.h b/base/bind.h index 7a400af..1070ce6d 100644 --- a/base/bind.h +++ b/base/bind.h
@@ -187,18 +187,15 @@ // well-formed. Using `Invoker::Run` with a OnceCallback triggers a // static_assert, which is why the ternary expression does not compile. // TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`. -template <bool is_once, typename Invoker> -struct InvokeFuncImpl; +template <typename Invoker> +constexpr auto GetInvokeFunc(std::true_type) { + return Invoker::RunOnce; +} template <typename Invoker> -struct InvokeFuncImpl<true, Invoker> { - static constexpr auto Value = &Invoker::RunOnce; -}; - -template <typename Invoker> -struct InvokeFuncImpl<false, Invoker> { - static constexpr auto Value = &Invoker::Run; -}; +constexpr auto GetInvokeFunc(std::false_type) { + return Invoker::Run; +} template <template <typename> class CallbackT, typename Functor, @@ -229,7 +226,8 @@ // InvokeFuncStorage, so that we can ensure its type matches to // PolymorphicInvoke, to which CallbackType will cast back. using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; - PolymorphicInvoke invoke_func = InvokeFuncImpl<kIsOnce, Invoker>::Value; + PolymorphicInvoke invoke_func = + GetInvokeFunc<Invoker>(std::integral_constant<bool, kIsOnce>()); using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; return CallbackType(BindState::Create(
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn index 780f752..797e8ce 100644 --- a/build/config/mac/BUILD.gn +++ b/build/config/mac/BUILD.gn
@@ -77,7 +77,7 @@ # macros that collide with common names, like 'check', 'require', and # 'verify'. # http://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/AssertMacros.h - defines = [ "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE=0" ] + defines = [ "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0" ] } # On Mac, this is used for everything except static libraries.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 41ba5ef..b0d706f 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8899327402780790352 \ No newline at end of file +8899266194319676112 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index b83e199..3b033af 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8899333129287039888 \ No newline at end of file +8899267142825427424 \ No newline at end of file
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc index 0f0dbf85..cb494e6 100644 --- a/cc/metrics/compositor_frame_reporter.cc +++ b/cc/metrics/compositor_frame_reporter.cc
@@ -153,6 +153,17 @@ EndCurrentStage(frame_termination_time_); } +void CompositorFrameReporter::OnFinishImplFrame(base::TimeTicks timestamp) { + DCHECK(!did_finish_impl_frame_); + + did_finish_impl_frame_ = true; + impl_frame_finish_time_ = timestamp; +} + +void CompositorFrameReporter::OnAbortBeginMainFrame() { + did_abort_main_frame_ = false; +} + void CompositorFrameReporter::SetVizBreakdown( const viz::FrameTimingDetails& viz_breakdown) { DCHECK(current_stage_.viz_breakdown.received_compositor_frame_timestamp @@ -161,7 +172,8 @@ } void CompositorFrameReporter::TerminateReporter() { - DCHECK_EQ(current_stage_.start_time, base::TimeTicks()); + if (frame_termination_status_ != FrameTerminationStatus::kUnknown) + DCHECK_EQ(current_stage_.start_time, base::TimeTicks()); bool report_latency = false; const char* termination_status_str = nullptr; switch (frame_termination_status_) { @@ -186,7 +198,7 @@ termination_status_str = "did_not_produce_frame"; break; case FrameTerminationStatus::kUnknown: - NOTREACHED(); + termination_status_str = "terminated_before_ending"; break; } const char* submission_status_str =
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h index ad2b53e..79cbd089 100644 --- a/cc/metrics/compositor_frame_reporter.h +++ b/cc/metrics/compositor_frame_reporter.h
@@ -111,6 +111,14 @@ int StageHistorySizeForTesting() { return stage_history_.size(); } + void OnFinishImplFrame(base::TimeTicks timestamp); + void OnAbortBeginMainFrame(); + bool did_finish_impl_frame() const { return did_finish_impl_frame_; } + bool did_abort_main_frame() const { return did_abort_main_frame_; } + base::TimeTicks impl_frame_finish_time() const { + return impl_frame_finish_time_; + } + protected: struct StageData { StageType stage_type; @@ -161,6 +169,14 @@ FrameTerminationStatus::kUnknown; const base::flat_set<FrameSequenceTrackerType>* active_trackers_; + + // Indicates if work on Impl frame is finished. + bool did_finish_impl_frame_ = false; + // Indicates if main frame is aborted after begin. + bool did_abort_main_frame_ = false; + // The time that work on Impl frame is finished. It's only valid if the + // reporter is in a stage other than begin impl frame. + base::TimeTicks impl_frame_finish_time_; }; } // namespace cc
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc index 0fea655c..760207b 100644 --- a/cc/metrics/compositor_frame_reporting_controller.cc +++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -59,43 +59,60 @@ std::unique_ptr<CompositorFrameReporter> reporter = std::make_unique<CompositorFrameReporter>(&active_trackers_, is_single_threaded_); - reporter->StartStage( - CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, - begin_time); + reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame, + begin_time); reporters_[PipelineStage::kBeginImplFrame] = std::move(reporter); } void CompositorFrameReportingController::WillBeginMainFrame() { - DCHECK(reporters_[PipelineStage::kBeginImplFrame]); - // We need to use .get() below because operator<< in std::unique_ptr is a - // C++20 feature. - DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(), - reporters_[PipelineStage::kBeginImplFrame].get()); - reporters_[PipelineStage::kBeginImplFrame]->StartStage( - CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); - AdvanceReporterStage(PipelineStage::kBeginImplFrame, - PipelineStage::kBeginMainFrame); + if (reporters_[PipelineStage::kBeginImplFrame]) { + // We need to use .get() below because operator<< in std::unique_ptr is a + // C++20 feature. + DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(), + reporters_[PipelineStage::kBeginImplFrame].get()); + reporters_[PipelineStage::kBeginImplFrame]->StartStage( + StageType::kSendBeginMainFrameToCommit, Now()); + AdvanceReporterStage(PipelineStage::kBeginImplFrame, + PipelineStage::kBeginMainFrame); + } else { + // In this case we have already submitted the ImplFrame, but we received + // beginMain frame before next BeginImplFrame (Not reached the ImplFrame + // deadline yet). So will start a new reporter at BeginMainFrame. + std::unique_ptr<CompositorFrameReporter> reporter = + std::make_unique<CompositorFrameReporter>(&active_trackers_, + is_single_threaded_); + reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now()); + reporters_[PipelineStage::kBeginMainFrame] = std::move(reporter); + } } void CompositorFrameReportingController::BeginMainFrameAborted() { DCHECK(reporters_[PipelineStage::kBeginMainFrame]); - std::unique_ptr<CompositorFrameReporter> aborted_frame_reporter = - std::move(reporters_[PipelineStage::kBeginMainFrame]); - aborted_frame_reporter->TerminateFrame( - CompositorFrameReporter::FrameTerminationStatus::kMainFrameAborted, - Now()); + + auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame]; + begin_main_reporter->OnAbortBeginMainFrame(); + + // If the main-frame was aborted (e.g. there was no visible update), then + // advance to activate stage if the compositor has already made changes to + // the active tree (i.e. if impl-frame has finished). + if (begin_main_reporter->did_finish_impl_frame()) { + begin_main_reporter->StartStage( + StageType::kEndActivateToSubmitCompositorFrame, Now()); + AdvanceReporterStage(PipelineStage::kBeginMainFrame, + PipelineStage::kActivate); + } } void CompositorFrameReportingController::WillCommit() { DCHECK(reporters_[PipelineStage::kBeginMainFrame]); - reporters_[PipelineStage::kBeginMainFrame]->StartStage( - CompositorFrameReporter::StageType::kCommit, Now()); + reporters_[PipelineStage::kBeginMainFrame]->StartStage(StageType::kCommit, + Now()); } void CompositorFrameReportingController::DidCommit() { DCHECK(reporters_[PipelineStage::kBeginMainFrame]); reporters_[PipelineStage::kBeginMainFrame]->StartStage( - CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); + StageType::kEndCommitToActivation, Now()); AdvanceReporterStage(PipelineStage::kBeginMainFrame, PipelineStage::kCommit); } @@ -109,8 +126,7 @@ DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_); if (!reporters_[PipelineStage::kCommit]) return; - reporters_[PipelineStage::kCommit]->StartStage( - CompositorFrameReporter::StageType::kActivation, Now()); + reporters_[PipelineStage::kCommit]->StartStage(StageType::kActivation, Now()); } void CompositorFrameReportingController::DidActivate() { @@ -119,25 +135,57 @@ if (!reporters_[PipelineStage::kCommit]) return; reporters_[PipelineStage::kCommit]->StartStage( - CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, - Now()); + StageType::kEndActivateToSubmitCompositorFrame, Now()); AdvanceReporterStage(PipelineStage::kCommit, PipelineStage::kActivate); } void CompositorFrameReportingController::DidSubmitCompositorFrame( uint32_t frame_token) { + // If there is no reporter in active stage and there exists a finished + // BeginImplFrame reporter (i.e. if impl-frame has finished), then advance it + // to the activate stage. + if (!reporters_[PipelineStage::kActivate] && + reporters_[PipelineStage::kBeginImplFrame]) { + auto& begin_impl_frame = reporters_[PipelineStage::kBeginImplFrame]; + if (begin_impl_frame->did_finish_impl_frame()) { + begin_impl_frame->StartStage( + StageType::kEndActivateToSubmitCompositorFrame, + begin_impl_frame->impl_frame_finish_time()); + AdvanceReporterStage(PipelineStage::kBeginImplFrame, + PipelineStage::kActivate); + } + } + if (!reporters_[PipelineStage::kActivate]) return; + std::unique_ptr<CompositorFrameReporter> submitted_reporter = std::move(reporters_[PipelineStage::kActivate]); submitted_reporter->StartStage( - CompositorFrameReporter::StageType:: - kSubmitCompositorFrameToPresentationCompositorFrame, - Now()); + StageType::kSubmitCompositorFrameToPresentationCompositorFrame, Now()); submitted_compositor_frames_.emplace_back(frame_token, std::move(submitted_reporter)); } +void CompositorFrameReportingController::OnFinishImplFrame() { + if (reporters_[PipelineStage::kBeginImplFrame]) { + reporters_[PipelineStage::kBeginImplFrame]->OnFinishImplFrame(Now()); + } else if (reporters_[PipelineStage::kBeginMainFrame]) { + auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame]; + begin_main_reporter->OnFinishImplFrame(Now()); + + // If the main-frame was aborted (e.g. there was no visible update), then + // advance to activate stage if the compositor has already made changes to + // the active tree (i.e. if impl-frame has finished). + if (begin_main_reporter->did_abort_main_frame()) { + begin_main_reporter->StartStage( + StageType::kEndActivateToSubmitCompositorFrame, Now()); + AdvanceReporterStage(PipelineStage::kBeginMainFrame, + PipelineStage::kActivate); + } + } +} + void CompositorFrameReportingController::DidPresentCompositorFrame( uint32_t frame_token, const viz::FrameTimingDetails& details) {
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h index 997d26b..80254c1d 100644 --- a/cc/metrics/compositor_frame_reporting_controller.h +++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -57,6 +57,7 @@ virtual void WillActivate(); virtual void DidActivate(); virtual void DidSubmitCompositorFrame(uint32_t frame_token); + virtual void OnFinishImplFrame(); virtual void DidPresentCompositorFrame( uint32_t frame_token, const viz::FrameTimingDetails& details);
diff --git a/cc/metrics/compositor_timing_history.cc b/cc/metrics/compositor_timing_history.cc index 6991812..d244237b 100644 --- a/cc/metrics/compositor_timing_history.cc +++ b/cc/metrics/compositor_timing_history.cc
@@ -735,6 +735,8 @@ void CompositorTimingHistory::WillFinishImplFrame(bool needs_redraw) { if (!needs_redraw) SetCompositorDrawingContinuously(false); + + compositor_frame_reporting_controller_->OnFinishImplFrame(); } void CompositorTimingHistory::BeginImplFrameNotExpectedSoon() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java index be206ff..d21c62d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
@@ -11,6 +11,7 @@ import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.browser.WarmupManager; import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.omnibox.LocationBarVoiceRecognitionHandler.VoiceResult; @@ -54,7 +55,8 @@ public AutocompleteController(Profile profile, OnSuggestionsReceivedListener listener) { if (profile != null) { - mNativeAutocompleteControllerAndroid = nativeInit(profile); + mNativeAutocompleteControllerAndroid = + AutocompleteControllerJni.get().init(AutocompleteController.this, profile); } mListener = listener; } @@ -76,7 +78,8 @@ return; } - mNativeAutocompleteControllerAndroid = nativeInit(profile); + mNativeAutocompleteControllerAndroid = + AutocompleteControllerJni.get().init(AutocompleteController.this, profile); } /** @@ -108,10 +111,12 @@ TextUtils.isEmpty(url)); if (profile == null || TextUtils.isEmpty(url)) return; - mNativeAutocompleteControllerAndroid = nativeInit(profile); + mNativeAutocompleteControllerAndroid = + AutocompleteControllerJni.get().init(AutocompleteController.this, profile); // Initializing the native counterpart might still fail. if (mNativeAutocompleteControllerAndroid != 0) { - nativeStart(mNativeAutocompleteControllerAndroid, text, cursorPosition, null, url, + AutocompleteControllerJni.get().start(mNativeAutocompleteControllerAndroid, + AutocompleteController.this, text, cursorPosition, null, url, pageClassification, preventInlineAutocomplete, false, false, true); mWaitingForSuggestionsToCache = false; } @@ -134,7 +139,8 @@ */ public OmniboxSuggestion classify(String text, boolean focusedFromFakebox) { if (mNativeAutocompleteControllerAndroid != 0) { - return nativeClassify(mNativeAutocompleteControllerAndroid, text, focusedFromFakebox); + return AutocompleteControllerJni.get().classify(mNativeAutocompleteControllerAndroid, + AutocompleteController.this, text, focusedFromFakebox); } return null; } @@ -157,11 +163,12 @@ // especially if a Service Worker is used. WarmupManager.getInstance().createSpareRenderProcessHost(profile); } - mNativeAutocompleteControllerAndroid = nativeInit(profile); + mNativeAutocompleteControllerAndroid = + AutocompleteControllerJni.get().init(AutocompleteController.this, profile); if (mNativeAutocompleteControllerAndroid != 0) { if (mUseCachedZeroSuggestResults) mWaitingForSuggestionsToCache = true; - nativeOnOmniboxFocused(mNativeAutocompleteControllerAndroid, omniboxText, url, - pageClassification, title); + AutocompleteControllerJni.get().onOmniboxFocused(mNativeAutocompleteControllerAndroid, + AutocompleteController.this, omniboxText, url, pageClassification, title); } } @@ -183,7 +190,8 @@ if (mNativeAutocompleteControllerAndroid != 0) { // crbug.com/764749 Log.w(TAG, "stopping autocomplete."); - nativeStop(mNativeAutocompleteControllerAndroid, clear); + AutocompleteControllerJni.get().stop( + mNativeAutocompleteControllerAndroid, AutocompleteController.this, clear); } } @@ -193,7 +201,8 @@ */ void resetSession() { if (mNativeAutocompleteControllerAndroid != 0) { - nativeResetSession(mNativeAutocompleteControllerAndroid); + AutocompleteControllerJni.get().resetSession( + mNativeAutocompleteControllerAndroid, AutocompleteController.this); } } @@ -203,7 +212,8 @@ */ void deleteSuggestion(int position, int hashCode) { if (mNativeAutocompleteControllerAndroid != 0) { - nativeDeleteSuggestion(mNativeAutocompleteControllerAndroid, position, hashCode); + AutocompleteControllerJni.get().deleteSuggestion(mNativeAutocompleteControllerAndroid, + AutocompleteController.this, position, hashCode); } } @@ -256,9 +266,9 @@ assert mNativeAutocompleteControllerAndroid != 0; // Don't natively log voice suggestion results as we add them in Java. if (type == OmniboxSuggestionType.VOICE_SUGGEST) return; - nativeOnSuggestionSelected(mNativeAutocompleteControllerAndroid, selectedIndex, hashCode, - currentPageUrl, pageClassification, elapsedTimeSinceModified, completedLength, - webContents); + AutocompleteControllerJni.get().onSuggestionSelected(mNativeAutocompleteControllerAndroid, + AutocompleteController.this, selectedIndex, hashCode, currentPageUrl, + pageClassification, elapsedTimeSinceModified, completedLength, webContents); } /** @@ -332,45 +342,49 @@ */ String updateMatchDestinationUrlWithQueryFormulationTime( int selectedIndex, int hashCode, long elapsedTimeSinceInputChange) { - return nativeUpdateMatchDestinationURLWithQueryFormulationTime( - mNativeAutocompleteControllerAndroid, selectedIndex, hashCode, - elapsedTimeSinceInputChange); + return AutocompleteControllerJni.get().updateMatchDestinationURLWithQueryFormulationTime( + mNativeAutocompleteControllerAndroid, AutocompleteController.this, selectedIndex, + hashCode, elapsedTimeSinceInputChange); } - @VisibleForTesting - protected native long nativeInit(Profile profile); - private native void nativeStart(long nativeAutocompleteControllerAndroid, String text, - int cursorPosition, String desiredTld, String currentUrl, int pageClassification, - boolean preventInlineAutocomplete, boolean preferKeyword, - boolean allowExactKeywordMatch, boolean wantAsynchronousMatches); - private native OmniboxSuggestion nativeClassify( - long nativeAutocompleteControllerAndroid, String text, boolean focusedFromFakebox); - private native void nativeStop(long nativeAutocompleteControllerAndroid, boolean clearResults); - private native void nativeResetSession(long nativeAutocompleteControllerAndroid); - private native void nativeOnSuggestionSelected(long nativeAutocompleteControllerAndroid, - int selectedIndex, int hashCode, String currentPageUrl, int pageClassification, - long elapsedTimeSinceModified, int completedLength, WebContents webContents); - private native void nativeOnOmniboxFocused(long nativeAutocompleteControllerAndroid, - String omniboxText, String currentUrl, int pageClassification, String currentTitle); - private native void nativeDeleteSuggestion( - long nativeAutocompleteControllerAndroid, int selectedIndex, int hashCode); - private native String nativeUpdateMatchDestinationURLWithQueryFormulationTime( - long nativeAutocompleteControllerAndroid, int selectedIndex, int hashCode, - long elapsedTimeSinceInputChange); + @NativeMethods + interface Natives { + long init(AutocompleteController caller, Profile profile); + void start(long nativeAutocompleteControllerAndroid, AutocompleteController caller, + String text, int cursorPosition, String desiredTld, String currentUrl, + int pageClassification, boolean preventInlineAutocomplete, boolean preferKeyword, + boolean allowExactKeywordMatch, boolean wantAsynchronousMatches); + OmniboxSuggestion classify(long nativeAutocompleteControllerAndroid, + AutocompleteController caller, String text, boolean focusedFromFakebox); + void stop(long nativeAutocompleteControllerAndroid, AutocompleteController caller, + boolean clearResults); + void resetSession(long nativeAutocompleteControllerAndroid, AutocompleteController caller); + void onSuggestionSelected(long nativeAutocompleteControllerAndroid, + AutocompleteController caller, int selectedIndex, int hashCode, + String currentPageUrl, int pageClassification, long elapsedTimeSinceModified, + int completedLength, WebContents webContents); + void onOmniboxFocused(long nativeAutocompleteControllerAndroid, + AutocompleteController caller, String omniboxText, String currentUrl, + int pageClassification, String currentTitle); + void deleteSuggestion(long nativeAutocompleteControllerAndroid, + AutocompleteController caller, int selectedIndex, int hashCode); + String updateMatchDestinationURLWithQueryFormulationTime( + long nativeAutocompleteControllerAndroid, AutocompleteController caller, + int selectedIndex, int hashCode, long elapsedTimeSinceInputChange); + /** + * Given a search query, this will attempt to see if the query appears to be portion of a + * properly formed URL. If it appears to be a URL, this will return the fully qualified + * version (i.e. including the scheme, etc...). If the query does not appear to be a URL, + * this will return null. + * + * @param query The query to be expanded into a fully qualified URL if appropriate. + * @return The fully qualified URL or null. + */ + String qualifyPartialURLQuery(String query); - /** - * Given a search query, this will attempt to see if the query appears to be portion of a - * properly formed URL. If it appears to be a URL, this will return the fully qualified - * version (i.e. including the scheme, etc...). If the query does not appear to be a URL, - * this will return null. - * - * @param query The query to be expanded into a fully qualified URL if appropriate. - * @return The fully qualified URL or null. - */ - static native String nativeQualifyPartialURLQuery(String query); - - /** - * Sends a zero suggest request to the server in order to pre-populate the result cache. - */ - static native void nativePrefetchZeroSuggestResults(); + /** + * Sends a zero suggest request to the server in order to pre-populate the result cache. + */ + void prefetchZeroSuggestResults(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorFactory.java index bae7657..21ef03ba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorFactory.java
@@ -32,7 +32,7 @@ /** * Temporary shortcut for {@link org.chromium.chrome.browser.IntentHandler} to access - * {@link AutocompleteController#nativeQualifyPartialURLQuery(String)} without having an + * {@link AutocompleteControllerJni.get().qualifyPartialURLQuery(String)} without having an * instance of {@link AutocompleteCoordinator}. * * TODO(crbug.com/966424): Fix the dependency issue and remove this method. @@ -42,6 +42,6 @@ */ @Deprecated public static String qualifyPartialURLQuery(String query) { - return AutocompleteController.nativeQualifyPartialURLQuery(query); + return AutocompleteControllerJni.get().qualifyPartialURLQuery(query); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java index e32b714..4687001 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
@@ -265,12 +265,12 @@ @Override public String qualifyPartialURLQuery(String query) { - return AutocompleteController.nativeQualifyPartialURLQuery(query); + return AutocompleteControllerJni.get().qualifyPartialURLQuery(query); } @Override public void prefetchZeroSuggestResults() { - AutocompleteController.nativePrefetchZeroSuggestResults(); + AutocompleteControllerJni.get().prefetchZeroSuggestResults(); } @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index 979daa9..dd27c7d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -381,7 +381,7 @@ private void maybeTriggerCacheRefresh(String url) { if (url == null) return; if (!UrlConstants.NTP_URL.equals(url)) return; - AutocompleteController.nativePrefetchZeroSuggestResults(); + AutocompleteControllerJni.get().prefetchZeroSuggestResults(); } }; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogMediator.java index 81c7b7d..66788993 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogMediator.java
@@ -20,9 +20,11 @@ import org.chromium.base.Callback; import org.chromium.base.VisibleForTesting; +import org.chromium.base.task.PostTask; import org.chromium.chrome.R; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.modaldialog.TabModalPresenter; +import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; @@ -120,7 +122,9 @@ int oldHeight = oldBottom - oldTop; int newHeight = bottom - top; if (newHeight == oldHeight) return; - mModel.set(ILLUSTRATION_VISIBLE, hasSufficientSpaceForIllustration(newHeight)); + PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> { + mModel.set(ILLUSTRATION_VISIBLE, hasSufficientSpaceForIllustration(newHeight)); + }); } void showDialog(@ModalDialogManager.ModalDialogType int type) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogView.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogView.java index e55c78c..4295cff 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogView.java
@@ -45,8 +45,6 @@ mIllustrationView.setVisibility(VISIBLE); } else { mIllustrationView.setVisibility(GONE); - requestLayout(); // Sometimes the visibility isn't propagated correctly and the image - // appears as INVISIBLE. } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java index c745bd56..3881c70 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -459,6 +459,9 @@ // This method should be called at most once per sign-in flow. assert mSignInState != null && mSignInState.mCoreAccountInfo != null; + // The user should not be already signed in + assert !mIdentityManager.hasPrimaryAccount(); + if (!mIdentityMutator.setPrimaryAccount(mSignInState.mCoreAccountInfo.getId())) { Log.w(TAG, "Failed to set the PrimaryAccount in IdentityManager, aborting signin"); abortSignIn();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogTest.java index b2cf64c..5b4816e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogTest.java
@@ -8,12 +8,10 @@ import static android.support.test.espresso.Espresso.pressBack; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.assertThat; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.verify; @@ -37,6 +35,7 @@ import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; @@ -135,7 +134,7 @@ mMediator.onLayoutChange(null, 0, 0, (int) (testWidthDipLandscape * dipScale), (int) (testHeightDipLandscape * dipScale), 0, 0, 0, 0); }); - assertThat(mModel.get(ILLUSTRATION_VISIBLE), is(false)); + CriteriaHelper.pollUiThread(() -> !mModel.get(ILLUSTRATION_VISIBLE)); // Dimensions resembling portrait orientation. final int testHeightDipPortrait = 500; @@ -144,7 +143,7 @@ mMediator.onLayoutChange(null, 0, 0, (int) (testWidthDipPortrait * dipScale), (int) (testHeightDipPortrait * dipScale), 0, 0, 0, 0); }); - assertThat(mModel.get(ILLUSTRATION_VISIBLE), is(true)); + CriteriaHelper.pollUiThread(() -> mModel.get(ILLUSTRATION_VISIBLE)); // Dimensions resembling multi-window mode. final int testHeightDipMultiWindow = 250; @@ -153,6 +152,6 @@ mMediator.onLayoutChange(null, 0, 0, (int) (testWidthDipMultiWindow * dipScale), (int) (testHeightDipMultiWindow * dipScale), 0, 0, 0, 0); }); - assertThat(mModel.get(ILLUSTRATION_VISIBLE), is(false)); + CriteriaHelper.pollUiThread(() -> !mModel.get(ILLUSTRATION_VISIBLE)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcherTest.java index f038b4d..b02dc89 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcherTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcherTest.java
@@ -290,7 +290,7 @@ // If the CONTENT_SETTINGS_NUM_TYPES value changes *and* a new value has been exposed on // Android, then please update this code block to include a test for your new type. // Otherwise, just update count in the assert. - Assert.assertEquals(53, ContentSettingsType.CONTENT_SETTINGS_NUM_TYPES); + Assert.assertEquals(54, ContentSettingsType.CONTENT_SETTINGS_NUM_TYPES); websitePreferenceBridge.addContentSettingException( new ContentSettingException(ContentSettingsType.CONTENT_SETTINGS_TYPE_COOKIES, googleOrigin, ContentSettingValues.DEFAULT, preferenceSource));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java index 1bf85d80..bd6e39de4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
@@ -222,6 +222,7 @@ doReturn(account) .when(mIdentityManager) .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(any()); + doReturn(false).when(mIdentityManager).hasPrimaryAccount(); doReturn(true).when(mIdentityMutator).setPrimaryAccount(any()); doNothing().when(mIdentityMutator).reloadAllAccountsFromSystemWithPrimaryAccount(any()); @@ -237,4 +238,30 @@ assertFalse(mSigninManager.isOperationInProgress()); assertEquals(1, callCount.get()); } + + @Test(expected = AssertionError.class) + public void failIfAlreadySignedin() { + CoreAccountInfo account = new CoreAccountInfo(new CoreAccountId("test_at_gmail.com"), + new Account("test@gmail.com", AccountManagerFacade.GOOGLE_ACCOUNT_TYPE), + "test_at_gmail.com"); + + // No need to seed accounts to the native code. + doReturn(true).when(mAccountTrackerService).checkAndSeedSystemAccounts(); + // Request that policy is loaded. It will pause sign-in until onPolicyCheckedBeforeSignIn is + // invoked. + doNothing().when(mNativeMock).fetchAndApplyCloudPolicy(anyLong(), any(), any()); + + doReturn(account) + .when(mIdentityManager) + .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(any()); + doReturn(true).when(mIdentityManager).hasPrimaryAccount(); + + mSigninManager.onFirstRunCheckDone(); // Allow sign-in. + + mSigninManager.signIn(account.getAccount(), null); + assertTrue(mSigninManager.isOperationInProgress()); + + // The following should throw an assertion error + mSigninManager.finishSignInAfterPolicyEnforced(); + } }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 34d93246..42b899b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -5389,6 +5389,9 @@ sources = [ "flag-metadata.json", ] + inputs = [ + "//chrome/VERSION", + ] outputs = [ "$root_gen_dir/chrome/browser/expired_flags_list.cc", ]
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index 4eca632..70bab30 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -787,6 +787,10 @@ #if !defined(OS_ANDROID) host_content_settings_map_->ClearSettingsForOneTypeWithPredicate( + CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, delete_begin_, + delete_end_, website_settings_filter); + + host_content_settings_map_->ClearSettingsForOneTypeWithPredicate( CONTENT_SETTINGS_TYPE_INTENT_PICKER_DISPLAY, delete_begin_, delete_end_, website_settings_filter); #endif
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 9c66da9d..9b85c178e 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -94,6 +94,7 @@ #include "content/public/test/mock_download_manager.h" #include "content/public/test/test_utils.h" #include "mojo/public/cpp/bindings/remote.h" +#include "net/base/network_isolation_key.h" #include "net/cookies/canonical_cookie.h" #include "net/http/http_auth.h" #include "net/http/http_auth_cache.h" @@ -2461,20 +2462,23 @@ net::HttpAuthCache* http_auth_cache = http_session->http_auth_cache(); http_auth_cache->Add(kOrigin1, net::HttpAuth::AUTH_SERVER, kTestRealm, - net::HttpAuth::AUTH_SCHEME_BASIC, "test challenge", + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey(), "test challenge", net::AuthCredentials(base::ASCIIToUTF16("foo"), base::ASCIIToUTF16("bar")), "/"); CHECK(http_auth_cache->Lookup(kOrigin1, net::HttpAuth::AUTH_SERVER, - kTestRealm, net::HttpAuth::AUTH_SCHEME_BASIC)); + kTestRealm, net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); BlockUntilBrowsingDataRemoved( base::Time(), base::Time::Max(), ChromeBrowsingDataRemoverDelegate::DATA_TYPE_PASSWORDS, false); - EXPECT_EQ(nullptr, http_auth_cache->Lookup( - kOrigin1, net::HttpAuth::AUTH_SERVER, kTestRealm, - net::HttpAuth::AUTH_SCHEME_BASIC)); + EXPECT_EQ(nullptr, + http_auth_cache->Lookup( + kOrigin1, net::HttpAuth::AUTH_SERVER, kTestRealm, + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey())); } TEST_F(ChromeBrowsingDataRemoverDelegateTest, ClearPermissionPromptCounts) {
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc index ec30f25..95c1604 100644 --- a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc +++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
@@ -127,7 +127,12 @@ // Counting site usage data and durable permissions. auto* hcsm = HostContentSettingsMapFactory::GetForProfile(profile_); const ContentSettingsType content_settings[] = { - CONTENT_SETTINGS_TYPE_DURABLE_STORAGE, CONTENT_SETTINGS_TYPE_APP_BANNER}; + CONTENT_SETTINGS_TYPE_DURABLE_STORAGE, + CONTENT_SETTINGS_TYPE_APP_BANNER, +#if !defined(OS_ANDROID) + CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, +#endif + }; for (auto type : content_settings) { tasks_ += 1; GetOriginsFromHostContentSettignsMap(hcsm, type);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index de048af..339ac92 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -2183,10 +2183,14 @@ "usb/cros_usb_detector.h", "virtual_machines/virtual_machines_util.cc", "virtual_machines/virtual_machines_util.h", + "wilco_dtc_supportd/fake_wilco_dtc_supportd_client.cc", + "wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h", "wilco_dtc_supportd/mojo_utils.cc", "wilco_dtc_supportd/mojo_utils.h", "wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc", "wilco_dtc_supportd/wilco_dtc_supportd_bridge.h", + "wilco_dtc_supportd/wilco_dtc_supportd_client.cc", + "wilco_dtc_supportd/wilco_dtc_supportd_client.h", "wilco_dtc_supportd/wilco_dtc_supportd_manager.cc", "wilco_dtc_supportd/wilco_dtc_supportd_manager.h", "wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc",
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc index e12108f..2520ebc 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
@@ -525,14 +525,16 @@ ~AccessibilityManagerLoginTest() override = default; void SetUpOnMainThread() override { - OobeBaseTest::SetUpOnMainThread(); + // BrailleController has to be set before SetUpOnMainThread call as + // observers subscribe to the controller during SetUpOnMainThread. AccessibilityManager::SetBrailleControllerForTest(&braille_controller_); default_autoclick_delay_ = GetAutoclickDelay(); + OobeBaseTest::SetUpOnMainThread(); } void TearDownOnMainThread() override { - AccessibilityManager::SetBrailleControllerForTest(nullptr); OobeBaseTest::TearDownOnMainThread(); + AccessibilityManager::SetBrailleControllerForTest(nullptr); } void CreateSession(const AccountId& account_id) {
diff --git a/chrome/browser/chromeos/customization/customization_document.cc b/chrome/browser/chromeos/customization/customization_document.cc index 6ab83d7f..cb8c970 100644 --- a/chrome/browser/chromeos/customization/customization_document.cc +++ b/chrome/browser/chromeos/customization/customization_document.cc
@@ -39,6 +39,7 @@ #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" +#include "chromeos/constants/chromeos_paths.h" #include "chromeos/system/statistics_provider.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_registry_simple.h" @@ -73,10 +74,6 @@ const char kAcceptedManifestVersion[] = "1.0"; -// Path to OEM partner startup customization manifest. -const char kStartupCustomizationManifestPath[] = - "/opt/oem/etc/startup_manifest.json"; - // This is subdirectory relative to PathService(DIR_CHROMEOS_CUSTOM_WALLPAPERS), // where downloaded (and resized) wallpaper is stored. const char kCustomizationDefaultWallpaperDir[] = "customization"; @@ -287,7 +284,10 @@ // Loading manifest causes us to do blocking IO on UI thread. // Temporarily allow it until we fix http://crosbug.com/11103 base::ThreadRestrictions::ScopedAllowIO allow_io; - LoadManifestFromFile(base::FilePath(kStartupCustomizationManifestPath)); + base::FilePath startup_customization_manifest; + base::PathService::Get(chromeos::FILE_STARTUP_CUSTOMIZATION_MANIFEST, + &startup_customization_manifest); + LoadManifestFromFile(startup_customization_manifest); } Init(system::StatisticsProvider::GetInstance()); }
diff --git a/chrome/browser/chromeos/dbus/dbus_helper.cc b/chrome/browser/chromeos/dbus/dbus_helper.cc index 674fbba0..0a5fb39 100644 --- a/chrome/browser/chromeos/dbus/dbus_helper.cc +++ b/chrome/browser/chromeos/dbus/dbus_helper.cc
@@ -7,6 +7,7 @@ #include "base/path_service.h" #include "base/system/sys_info.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chrome/common/chrome_paths.h" #include "chromeos/constants/chromeos_paths.h" #include "chromeos/cryptohome/system_salt_getter.h" @@ -84,11 +85,13 @@ void InitializeFeatureListDependentDBus() { dbus::Bus* bus = DBusThreadManager::Get()->GetSystemBus(); InitializeDBusClient<bluez::BluezDBusManager>(bus); + InitializeDBusClient<WilcoDtcSupportdClient>(bus); } void ShutdownDBus() { - // Feature list-dependent D-Bus clients are shut down first because we try to. + // Feature list-dependent D-Bus clients are shut down first because we try to // shut down in reverse order of initialization (in case of dependencies). + WilcoDtcSupportdClient::Shutdown(); bluez::BluezDBusManager::Shutdown(); // Other D-Bus clients are shut down, also in reverse order of initialization.
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc index 7a71ce6..24bc3bc7 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -33,6 +33,7 @@ #include "base/metrics/histogram_base.h" #include "base/metrics/histogram_samples.h" #include "base/metrics/statistics_recorder.h" +#include "base/run_loop.h" #include "base/scoped_observer.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" @@ -88,6 +89,7 @@ #include "chromeos/services/machine_learning/public/cpp/service_connection.h" #include "components/arc/arc_prefs.h" #include "components/arc/metrics/arc_metrics_constants.h" +#include "components/policy/core/common/policy_service.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/histogram_fetcher.h" #include "extensions/browser/event_router.h" @@ -668,6 +670,26 @@ } /////////////////////////////////////////////////////////////////////////////// +// AutotestPrivateRefreshEnterprisePoliciesFunction +/////////////////////////////////////////////////////////////////////////////// + +AutotestPrivateRefreshEnterprisePoliciesFunction:: + ~AutotestPrivateRefreshEnterprisePoliciesFunction() = default; + +ExtensionFunction::ResponseAction +AutotestPrivateRefreshEnterprisePoliciesFunction::Run() { + DVLOG(1) << "AutotestPrivateRefreshEnterprisePoliciesFunction"; + + g_browser_process->policy_service()->RefreshPolicies(base::Bind( + &AutotestPrivateRefreshEnterprisePoliciesFunction::RefreshDone, this)); + return RespondLater(); +} + +void AutotestPrivateRefreshEnterprisePoliciesFunction::RefreshDone() { + Respond(NoArguments()); +} + +/////////////////////////////////////////////////////////////////////////////// // AutotestPrivateGetExtensionsInfoFunction ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h index b4bd816f..785425d3 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -502,6 +502,20 @@ ResponseAction Run() override; }; +class AutotestPrivateRefreshEnterprisePoliciesFunction + : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("autotestPrivate.refreshEnterprisePolicies", + AUTOTESTPRIVATE_REFRESHENTERPRISEPOLICIES) + + private: + ~AutotestPrivateRefreshEnterprisePoliciesFunction() override; + ResponseAction Run() override; + + // Called once all the policies have been refreshed. + void RefreshDone(); +}; + class AutotestPrivateBootstrapMachineLearningServiceFunction : public ExtensionFunction { public:
diff --git a/chrome/browser/chromeos/login/accessibility_browsertest.cc b/chrome/browser/chromeos/login/accessibility_browsertest.cc new file mode 100644 index 0000000..1c46820 --- /dev/null +++ b/chrome/browser/chromeos/login/accessibility_browsertest.cc
@@ -0,0 +1,131 @@ +// Copyright 2019 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 "ash/public/cpp/docked_magnifier_controller.h" +#include "ash/public/cpp/keyboard/keyboard_controller.h" +#include "chrome/browser/chromeos/accessibility/accessibility_manager.h" +#include "chrome/browser/chromeos/accessibility/magnification_manager.h" +#include "chrome/browser/chromeos/login/test/oobe_base_test.h" +#include "chrome/browser/chromeos/login/ui/login_display_host.h" +#include "chrome/browser/chromeos/login/ui/webui_login_view.h" +#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/view_observer.h" + +namespace chromeos { + +class DockedMagnifierVirtualKeyboardTest + : public OobeBaseTest, + public views::ViewObserver, + public ChromeKeyboardControllerClient::Observer { + public: + DockedMagnifierVirtualKeyboardTest() = default; + ~DockedMagnifierVirtualKeyboardTest() override = default; + + protected: + ChromeKeyboardControllerClient* keyboard_controller() { + return ChromeKeyboardControllerClient::Get(); + } + + MagnificationManager* magnification_manager() { + return MagnificationManager::Get(); + } + + WebUILoginView* webui_login_view() { + return LoginDisplayHost::default_host()->GetWebUILoginView(); + } + + gfx::Rect GetOobeBounds() { return webui_login_view()->GetBoundsInScreen(); } + + void ShowDockedMagnifier() { + magnification_manager()->SetDockedMagnifierEnabled(true); + ASSERT_TRUE(magnification_manager()->IsDockedMagnifierEnabled()); + ASSERT_GT(GetMagnifierHeight(), 0); + } + + void HideDockedMagnifier() { + magnification_manager()->SetDockedMagnifierEnabled(false); + ASSERT_FALSE(magnification_manager()->IsDockedMagnifierEnabled()); + ASSERT_EQ(GetMagnifierHeight(), 0); + } + + int GetMagnifierHeight() { + return ash::DockedMagnifierController::Get() + ->GetMagnifierHeightForTesting(); + } + + void ShowKeyboard() { + AccessibilityManager::Get()->EnableVirtualKeyboard(true); + keyboard_controller()->ShowKeyboard(); + keyboard_controller()->SetKeyboardLocked(true); + WaitForBoundsToChange(); + ASSERT_GT(GetKeyboardHeight(), 0); + } + + void HideKeyboard() { + keyboard_controller()->HideKeyboard(ash::HideReason::kUser); + ASSERT_EQ(GetKeyboardHeight(), 0); + } + + int GetKeyboardHeight() { return keyboard_bounds_.height(); } + + void WaitForBoundsToChange() { + ASSERT_FALSE(run_loop_); + run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_->Run(); + run_loop_.reset(); + } + + private: + // views::ViewObserver: + void OnViewBoundsChanged(views::View* observed_view) override { + ASSERT_EQ(observed_view, webui_login_view()); + if (run_loop_) + run_loop_->Quit(); + } + + // ChromeKeyboardControllerClient::Observer: + void OnKeyboardOccludedBoundsChanged( + const gfx::Rect& screen_bounds) override { + keyboard_bounds_ = screen_bounds; + } + + // OobeBaseTest: + void SetUpOnMainThread() override { + OobeBaseTest::SetUpOnMainThread(); + webui_login_view()->views::View::AddObserver(this); + keyboard_controller()->AddObserver(this); + } + + void TearDownOnMainThread() override { + webui_login_view()->views::View::RemoveObserver(this); + keyboard_controller()->RemoveObserver(this); + OobeBaseTest::TearDownOnMainThread(); + } + + std::unique_ptr<base::RunLoop> run_loop_; + gfx::Rect keyboard_bounds_; +}; + +IN_PROC_BROWSER_TEST_F(DockedMagnifierVirtualKeyboardTest, WelcomeScreen) { + const gfx::Rect original_bounds = GetOobeBounds(); + gfx::Rect expected_bounds(original_bounds); + + ShowDockedMagnifier(); + expected_bounds.Inset(0, GetMagnifierHeight(), 0, 0); + EXPECT_EQ(expected_bounds, GetOobeBounds()); + + ShowKeyboard(); + expected_bounds.Inset(0, 0, 0, GetKeyboardHeight()); + EXPECT_EQ(expected_bounds, GetOobeBounds()); + + expected_bounds.Inset(0, -GetMagnifierHeight(), 0, 0); + HideDockedMagnifier(); + EXPECT_EQ(expected_bounds, GetOobeBounds()); + + HideKeyboard(); + EXPECT_EQ(original_bounds, GetOobeBounds()); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/error_screen_browsertest.cc b/chrome/browser/chromeos/login/error_screen_browsertest.cc index ff86bd14..1a0f7b6 100644 --- a/chrome/browser/chromeos/login/error_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/error_screen_browsertest.cc
@@ -184,7 +184,7 @@ } // Test HideCallback is called after screen hides. -IN_PROC_BROWSER_TEST_F(NetworkErrorScreenTest, DISABLED_HideCallback) { +IN_PROC_BROWSER_TEST_F(NetworkErrorScreenTest, HideCallback) { bool callback_called = false; GetScreen()->SetHideCallback( base::BindLambdaForTesting([&]() { callback_called = true; }));
diff --git a/chrome/browser/chromeos/login/profile_auth_data_unittest.cc b/chrome/browser/chromeos/login/profile_auth_data_unittest.cc index f65e74d..a984c13 100644 --- a/chrome/browser/chromeos/login/profile_auth_data_unittest.cc +++ b/chrome/browser/chromeos/login/profile_auth_data_unittest.cc
@@ -23,6 +23,7 @@ #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_utils.h" #include "mojo/public/cpp/bindings/remote.h" +#include "net/base/network_isolation_key.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_constants.h" #include "net/http/http_auth.h" @@ -170,7 +171,8 @@ net::HttpAuthCache::Entry* entry = GetProxyAuth(user_browser_context_.network_context()) ->Lookup(GURL(kProxyAuthURL), net::HttpAuth::AUTH_SERVER, - kProxyAuthRealm, net::HttpAuth::AUTH_SCHEME_BASIC); + kProxyAuthRealm, net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(base::ASCIIToUTF16(kProxyAuthPassword1), entry->credentials().password()); @@ -205,7 +207,8 @@ const std::string& cookie_value) { GetProxyAuth(browser_context->network_context()) ->Add(GURL(kProxyAuthURL), net::HttpAuth::AUTH_SERVER, kProxyAuthRealm, - net::HttpAuth::AUTH_SCHEME_BASIC, kProxyAuthChallenge, + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + kProxyAuthChallenge, net::AuthCredentials(base::string16(), base::ASCIIToUTF16(proxy_auth_password)), std::string());
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc index 67fbeca..423bd9af 100644 --- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc +++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -77,7 +77,6 @@ #include "components/account_id/account_id.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings_types.h" -#include "components/guest_view/browser/test_guest_view_manager.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" @@ -95,7 +94,6 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" -#include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/common/features/feature_channel.h" #include "google_apis/gaia/fake_gaia.h" #include "google_apis/gaia/gaia_constants.h" @@ -831,22 +829,15 @@ void SetUpOnMainThread() override; void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) override; - guest_view::TestGuestViewManager* GetGuestViewManager(); - content::WebContents* GetEnrollmentContents(); - protected: LocalPolicyTestServerMixin local_policy_mixin_{&mixin_host_}; test::EnrollmentUIMixin enrollment_ui_{&mixin_host_}; - guest_view::TestGuestViewManagerFactory guest_view_manager_factory_; - private: DISALLOW_COPY_AND_ASSIGN(SAMLEnrollmentTest); }; SAMLEnrollmentTest::SAMLEnrollmentTest() { - guest_view::GuestViewManager::set_factory_for_testing( - &guest_view_manager_factory_); gaia_frame_parent_ = "oauth-enroll-auth-view"; authenticator_id_ = "$('enterprise-enrollment').authenticator_"; } @@ -867,32 +858,14 @@ void SAMLEnrollmentTest::StartSamlAndWaitForIdpPageLoad( const std::string& gaia_email) { - WaitForSigninScreen(); - ExistingUserController::current_controller()->OnStartEnterpriseEnrollment(); - while (!GetEnrollmentContents()) { - GetGuestViewManager()->WaitForNextGuestCreated(); - } - // Wait for Gaia is ready. - OobeBaseTest::WaitForGaiaPageEvent("backButton"); + LoginDisplayHost::default_host()->StartWizard( + EnrollmentScreenView::kScreenId); + WaitForGaiaPageBackButtonUpdate(); SigninFrameJS().TypeIntoPath(gaia_email, {"identifier"}); SigninFrameJS().TapOn("nextButton"); OobeBaseTest::WaitForGaiaPageEvent("authFlowChange"); } -guest_view::TestGuestViewManager* SAMLEnrollmentTest::GetGuestViewManager() { - return static_cast<guest_view::TestGuestViewManager*>( - guest_view::TestGuestViewManager::FromBrowserContext( - ProfileHelper::GetSigninProfile())); -} - -content::WebContents* SAMLEnrollmentTest::GetEnrollmentContents() { - content::RenderFrameHost* frame_host = - signin::GetAuthFrame(GetLoginUI()->GetWebContents(), gaia_frame_parent_); - if (!frame_host) - return nullptr; - return content::WebContents::FromRenderFrameHost(frame_host); -} - IN_PROC_BROWSER_TEST_F(SAMLEnrollmentTest, WithoutCredentialsPassingAPI) { fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html"); StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail); @@ -1106,7 +1079,6 @@ } void SAMLPolicyTest::ShowGAIALoginForm() { - login_screen_load_observer_->Wait(); content::DOMMessageQueue message_queue; ASSERT_TRUE(content::ExecuteScript( GetLoginUI()->GetWebContents(), @@ -1121,7 +1093,6 @@ } void SAMLPolicyTest::ShowSAMLInterstitial() { - login_screen_load_observer_->Wait(); WaitForOobeUI(); std::string js = @@ -1151,8 +1122,6 @@ } void SAMLPolicyTest::ClickNextOnSAMLInterstitialPage() { - login_screen_load_observer_->Wait(); - content::DOMMessageQueue message_queue; SetupAuthFlowChangeListener(); @@ -1168,8 +1137,6 @@ } void SAMLPolicyTest::ClickChangeAccountOnSAMLInterstitialPage() { - login_screen_load_observer_->Wait(); - std::string js = "$('gaia-signin').authenticator_.addEventListener('ready', function() {" " window.domAutomationController.send('ready');" @@ -1253,7 +1220,6 @@ // Verifies that the offline login time limit does not affect a user who // authenticated without SAML. IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, NoSAML) { - login_screen_load_observer_->Wait(); // Verify that offline login is allowed. test::OobeJS().ExpectTrue( "window.getComputedStyle(document.querySelector(" @@ -1270,7 +1236,6 @@ // Verifies that when no offline login time limit is set, a user who // authenticated with SAML is allowed to log in offline. IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, SAMLNoLimit) { - login_screen_load_observer_->Wait(); // Verify that offline login is allowed. test::OobeJS().ExpectTrue( "window.getComputedStyle(document.querySelector(" @@ -1287,7 +1252,6 @@ // Verifies that when the offline login time limit is exceeded for a user who // authenticated via SAML, that user is forced to log in online the next time. IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, SAMLZeroLimit) { - login_screen_load_observer_->Wait(); // Verify that offline login is not allowed. test::OobeJS().ExpectTrue( "window.getComputedStyle(document.querySelector("
diff --git a/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc b/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc index 7142308..641a1be 100644 --- a/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
@@ -147,8 +147,7 @@ WaitForScreenExit(); } -// TODO(https://crbug.com/1009916): Fix flakes and re-enable. -IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, DISABLED_FingerprintDisabled) { +IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintDisabled) { quick_unlock::EnabledForTesting(false); fingerprint_setup_screen_->Show();
diff --git a/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc index c1feaaf1..320c478 100644 --- a/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc
@@ -161,9 +161,7 @@ // Test that if there is no Bluetooth device connected on HID screen, the // Bluetooth adapter should be disabled after advancing to the next screen. -// Flaky. https://crbug.com/1010866 -IN_PROC_BROWSER_TEST_F(HIDDetectionScreenTest, - DISABLED_NoBluetoothDeviceConnected) { +IN_PROC_BROWSER_TEST_F(HIDDetectionScreenTest, NoBluetoothDeviceConnected) { OobeScreenWaiter(HIDDetectionView::kScreenId).Wait(); EXPECT_TRUE(adapter()->IsPowered());
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc index ccd0d909..1742e58 100644 --- a/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc
@@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> + +#include "base/test/scoped_path_override.h" +#include "base/test/task_environment.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" @@ -11,11 +15,17 @@ #include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/login/test/oobe_base_test.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" +#include "chrome/browser/chromeos/login/test/test_predicate_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" +#include "chromeos/constants/chromeos_paths.h" #include "chromeos/dbus/constants/dbus_switches.h" +#include "components/language/core/browser/pref_names.h" +#include "components/prefs/pref_service.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" #include "ui/accessibility/accessibility_switches.h" #include "ui/base/ime/chromeos/extension_ime_util.h" @@ -23,6 +33,14 @@ namespace { +const char kStartupManifest[] = + R"({ + "version": "1.0", + "initial_locale" : "en-US", + "initial_timezone" : "US/Pacific", + "keyboard_layout" : "xkb:us::eng", + })"; + chromeos::OobeUI* GetOobeUI() { auto* host = chromeos::LoginDisplayHost::default_host(); return host ? host->GetOobeUI() : nullptr; @@ -45,6 +63,27 @@ js.CreateWaiter(feature_toggle)->Wait(); } +class LanguageReloadObserver : public WelcomeScreen::Observer { + public: + explicit LanguageReloadObserver(WelcomeScreen* welcome_screen) + : welcome_screen_(welcome_screen) { + welcome_screen_->AddObserver(this); + } + + // WelcomeScreen::Observer: + void OnLanguageListReloaded() override { run_loop_.Quit(); } + + void Wait() { run_loop_.Run(); } + + ~LanguageReloadObserver() override { welcome_screen_->RemoveObserver(this); } + + private: + WelcomeScreen* const welcome_screen_; + base::RunLoop run_loop_; + + DISALLOW_COPY_AND_ASSIGN(LanguageReloadObserver); +}; + } // namespace class WelcomeScreenBrowserTest : public InProcessBrowserTest { @@ -55,8 +94,18 @@ // InProcessBrowserTest: void SetUpOnMainThread() override { - ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW); + ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); + base::FilePath startup_manifest = + data_dir_.GetPath().AppendASCII("startup_manifest.json"); + base::WriteFile(startup_manifest, kStartupManifest, + strlen(kStartupManifest)); + path_override_ = std::make_unique<base::ScopedPathOverride>( + chromeos::FILE_STARTUP_CUSTOMIZATION_MANIFEST, startup_manifest); + ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW); + test::TestPredicateWaiter(base::BindRepeating([]() { + return WizardController::default_controller() != nullptr; + })).Wait(); WizardController::default_controller() ->screen_manager() ->DeleteScreenForTesting(WelcomeView::kScreenId); @@ -65,12 +114,18 @@ base::BindRepeating(&WelcomeScreenBrowserTest::OnWelcomeScreenExit, base::Unretained(this))); welcome_screen_ = welcome_screen.get(); + observer_ = std::make_unique<LanguageReloadObserver>(welcome_screen_); WizardController::default_controller() ->screen_manager() ->SetScreenForTesting(std::move(welcome_screen)); InProcessBrowserTest::SetUpOnMainThread(); } + void TearDownOnMainThread() override { + observer_.reset(); + InProcessBrowserTest::TearDownOnMainThread(); + } + void WaitForScreenExit() { if (screen_exit_) return; @@ -87,8 +142,11 @@ } WelcomeScreen* welcome_screen_ = nullptr; + std::unique_ptr<LanguageReloadObserver> observer_; private: + std::unique_ptr<base::ScopedPathOverride> path_override_; + base::ScopedTempDir data_dir_; bool screen_exit_ = false; base::OnceClosure screen_exit_callback_; @@ -314,14 +372,35 @@ ASSERT_FALSE(MagnificationManager::Get()->IsMagnifierEnabled()); } -// Flaky. http://crbug.com/1010676 -IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, - DISABLED_A11yDockedMagnifierDisabled) { +IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, A11yDockedMagnifierDisabled) { welcome_screen_->Show(); OobeScreenWaiter(WelcomeView::kScreenId).Wait(); test::OobeJS().ExpectHiddenPath({"connect", "dockedMagnifierOobeOption"}); } +IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, PRE_SelectedLanguage) { + EXPECT_EQ( + StartupCustomizationDocument::GetInstance()->initial_locale_default(), + "en-US"); + welcome_screen_->Show(); + OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + const std::string locale = "ru"; + welcome_screen_->SetApplicationLocale(locale); + test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); + WaitForScreenExit(); + EXPECT_EQ(g_browser_process->local_state()->GetString( + language::prefs::kApplicationLocale), + locale); +} + +IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, SelectedLanguage) { + observer_->Wait(); + const std::string locale = "ru"; + EXPECT_EQ(g_browser_process->local_state()->GetString( + language::prefs::kApplicationLocale), + locale); +} + IN_PROC_BROWSER_TEST_F(WelcomeScreenWithExperimentalAccessibilityFeaturesTest, A11yDockedMagnifierEnabled) { welcome_screen_->Show();
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc index 14243e0..083d99a 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc +++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -304,11 +304,6 @@ } void LoginAsExistingUser() { - content::WindowedNotificationObserver( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()) - .Wait(); - test::OobeJS().ExpectTrue("!!document.querySelector('#account-picker')"); test::OobeJS().ExpectTrue("!!document.querySelector('#pod-row')"); @@ -572,11 +567,6 @@ IN_PROC_BROWSER_TEST_F(OAuth2Test, DISABLED_MergeSession) { SimulateNetworkOnline(); - content::WindowedNotificationObserver( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()) - .Wait(); - test::OobeJS().ExpectTrue("!!document.querySelector('#account-picker')"); test::OobeJS().ExpectTrue("!!document.querySelector('#pod-row')"); @@ -610,12 +600,6 @@ SetupGaiaServerForUnexpiredAccount(); SimulateNetworkOnline(); - // Waits for login screen to be ready. - content::WindowedNotificationObserver( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()) - .Wait(); - // Blocks database thread to control TokenService::LoadCredentials timing. // TODO(achuith): Fix this. crbug.com/753615. auto thread_blocker = std::make_unique<ThreadBlocker>(nullptr); @@ -730,12 +714,6 @@ SetupGaiaServerForUnexpiredAccount(); SimulateNetworkOnline(); - // Waits for login screen to be ready. - content::WindowedNotificationObserver( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()) - .Wait(); - // Signs in as the existing user created in pre test. ExistingUserController* const controller = ExistingUserController::current_controller();
diff --git a/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc b/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc index d05ca1754..3d190431 100644 --- a/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc +++ b/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc
@@ -24,6 +24,7 @@ #include "content/public/test/test_utils.h" #include "content/public/test/web_contents_tester.h" #include "mojo/public/cpp/bindings/remote.h" +#include "net/base/network_isolation_key.h" #include "net/cookies/cookie_store.h" #include "net/http/http_auth.h" #include "net/http/http_transaction_factory.h" @@ -52,8 +53,9 @@ ->GetSession() ->http_auth_cache(); http_auth_cache->Add(GURL(kEmbedderUrl), net::HttpAuth::AUTH_SERVER, "", - net::HttpAuth::AUTH_SCHEME_BASIC, "", - net::AuthCredentials(), ""); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey(), "", net::AuthCredentials(), + ""); } void IsEntryInHttpAuthCache(network::NetworkContext* network_context, @@ -64,7 +66,8 @@ ->http_auth_cache(); *out_entry_found = http_auth_cache->Lookup(GURL(kEmbedderUrl), net::HttpAuth::AUTH_SERVER, - "", net::HttpAuth::AUTH_SCHEME_BASIC) != nullptr; + "", net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey()) != nullptr; } } // namespace
diff --git a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc index b65b787..7fc4e60 100644 --- a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc +++ b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
@@ -114,13 +114,6 @@ OobeBaseTest::TearDownOnMainThread(); } - void WaitForUIToLoad() { - content::WindowedNotificationObserver observer( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()); - observer.Wait(); - } - void SwitchLanguage(const std::string& language) { const char get_num_reloads[] = "Oobe.getInstance().reloadContentNumEvents_"; const int prev_reloads = test::OobeJS().GetInt(get_num_reloads); @@ -212,7 +205,6 @@ }; IN_PROC_BROWSER_TEST_F(SyncConsentTest, SyncConsentRecorder) { - WaitForUIToLoad(); EXPECT_EQ(g_browser_process->GetApplicationLocale(), "en-US"); LoginToSyncConsentScreen(); // For En-US we hardcode strings here to catch string issues too. @@ -245,7 +237,6 @@ IN_PROC_BROWSER_TEST_P(SyncConsentTestWithParams, SyncConsentTestWithLocale) { LOG(INFO) << "SyncConsentTestWithParams() started with param='" << GetParam() << "'"; - WaitForUIToLoad(); EXPECT_EQ(g_browser_process->GetApplicationLocale(), "en-US"); SwitchLanguage(GetParam()); LoginToSyncConsentScreen();
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc index 0a00e46..096aa6e 100644 --- a/chrome/browser/chromeos/login/test/oobe_base_test.cc +++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -103,6 +103,7 @@ run_loop.QuitClosure())) { run_loop.Run(); } + MaybeWaitForLoginScreenLoad(); } void OobeBaseTest::WaitForGaiaPageLoad() { @@ -159,7 +160,7 @@ WizardController::SkipPostLoginScreensForTesting(); - login_screen_load_observer_->Wait(); + MaybeWaitForLoginScreenLoad(); } test::JSChecker OobeBaseTest::SigninFrameJS() { @@ -172,4 +173,11 @@ return result; } +void OobeBaseTest::MaybeWaitForLoginScreenLoad() { + if (!login_screen_load_observer_) + return; + login_screen_load_observer_->Wait(); + login_screen_load_observer_.reset(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.h b/chrome/browser/chromeos/login/test/oobe_base_test.h index 71deb2b..9dff976 100644 --- a/chrome/browser/chromeos/login/test/oobe_base_test.h +++ b/chrome/browser/chromeos/login/test/oobe_base_test.h
@@ -58,13 +58,18 @@ // is set before SetUpCommandLine is invoked. bool needs_background_networking_ = false; - std::unique_ptr<content::WindowedNotificationObserver> - login_screen_load_observer_; std::string gaia_frame_parent_ = "signin-frame"; std::string authenticator_id_ = "$('gaia-signin').authenticator_"; EmbeddedTestServerSetupMixin embedded_test_server_{&mixin_host_, embedded_test_server()}; + private: + // Waits for login_screen_load_observer_ and resets it afterwards. + void MaybeWaitForLoginScreenLoad(); + + std::unique_ptr<content::WindowedNotificationObserver> + login_screen_load_observer_; + DISALLOW_COPY_AND_ASSIGN(OobeBaseTest); };
diff --git a/chrome/browser/chromeos/login/test/oobe_screens_utils.cc b/chrome/browser/chromeos/login/test/oobe_screens_utils.cc index 47dae1d..53f78580 100644 --- a/chrome/browser/chromeos/login/test/oobe_screens_utils.cc +++ b/chrome/browser/chromeos/login/test/oobe_screens_utils.cc
@@ -42,10 +42,6 @@ } // namespace void WaitForWelcomeScreen() { - content::WindowedNotificationObserver observer( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()); - observer.Wait(); WaitFor(WelcomeView::kScreenId); }
diff --git a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc index 5edcf48..176b25e9 100644 --- a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc +++ b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
@@ -84,9 +84,6 @@ IN_PROC_BROWSER_TEST_F(ForceMaximizeOnFirstRunTest, TwoRuns) { SetUpResolution(); - content::WindowedNotificationObserver( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()).Wait(); LogIn(kAccountId, kAccountPassword, kEmptyServices); const Browser* const browser = OpenNewBrowserWindow();
diff --git a/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc b/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc index 1b290c7..1073577 100644 --- a/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc +++ b/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
@@ -85,9 +85,6 @@ // Verify that the policies are honored on an existing user's login. IN_PROC_BROWSER_TEST_F(RestoreOnStartupTestChromeOS, LogInAndVerify) { - content::WindowedNotificationObserver( - chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - content::NotificationService::AllSources()).Wait(); LogInAndVerifyStartUpURLs(); }
diff --git a/chromeos/dbus/fake_wilco_dtc_supportd_client.cc b/chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.cc similarity index 96% rename from chromeos/dbus/fake_wilco_dtc_supportd_client.cc rename to chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.cc index 78ca233..2d0f94c 100644 --- a/chromeos/dbus/fake_wilco_dtc_supportd_client.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h" #include <utility>
diff --git a/chromeos/dbus/fake_wilco_dtc_supportd_client.h b/chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h similarity index 82% rename from chromeos/dbus/fake_wilco_dtc_supportd_client.h rename to chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h index 94d71d8e..a56d26a 100644 --- a/chromeos/dbus/fake_wilco_dtc_supportd_client.h +++ b/chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h
@@ -2,21 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_DBUS_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_ -#define CHROMEOS_DBUS_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_ +#ifndef CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_ +#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_ #include <vector> #include "base/component_export.h" #include "base/macros.h" #include "base/optional.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chromeos/dbus/dbus_method_call_status.h" -#include "chromeos/dbus/wilco_dtc_supportd_client.h" namespace chromeos { -class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeWilcoDtcSupportdClient final - : public WilcoDtcSupportdClient { +class FakeWilcoDtcSupportdClient final : public WilcoDtcSupportdClient { public: FakeWilcoDtcSupportdClient(); ~FakeWilcoDtcSupportdClient() override; @@ -60,4 +59,4 @@ } // namespace chromeos -#endif // CHROMEOS_DBUS_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_ +#endif // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc b/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc index 1261b3e..937d8a3 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc
@@ -15,11 +15,10 @@ #include "base/posix/eintr_wrapper.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h" -#include "chromeos/dbus/wilco_dtc_supportd_client.h" namespace chromeos { @@ -130,9 +129,8 @@ }; FakeWilcoDtcSupportdClient* GetFakeDbusWilcoDtcSupportdClient() { - DCHECK(DBusThreadManager::Get()->IsUsingFakes()); WilcoDtcSupportdClient* const wilco_dtc_supportd_client = - DBusThreadManager::Get()->GetWilcoDtcSupportdClient(); + WilcoDtcSupportdClient::Get(); DCHECK(wilco_dtc_supportd_client); return static_cast<FakeWilcoDtcSupportdClient*>(wilco_dtc_supportd_client); }
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc index bc50074..f3454816 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc
@@ -15,11 +15,11 @@ #include "base/strings/string_piece.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_notification_controller.h" #include "chrome/browser/profiles/profile_manager.h" #include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/wilco_dtc_supportd_client.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/platform/platform_channel.h" @@ -160,11 +160,9 @@ // ScheduleWaitingForDBusService(). dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs(); - DBusThreadManager::Get() - ->GetWilcoDtcSupportdClient() - ->WaitForServiceToBeAvailable( - base::BindOnce(&WilcoDtcSupportdBridge::OnWaitedForDBusService, - dbus_waiting_weak_ptr_factory_.GetWeakPtr())); + chromeos::WilcoDtcSupportdClient::Get()->WaitForServiceToBeAvailable( + base::BindOnce(&WilcoDtcSupportdBridge::OnWaitedForDBusService, + dbus_waiting_weak_ptr_factory_.GetWeakPtr())); } void WilcoDtcSupportdBridge::ScheduleWaitingForDBusService() { @@ -221,12 +219,10 @@ // Send the file descriptor with the Mojo message pipe's remote endpoint to // the wilco_dtc_supportd daemon via the D-Bus. - DBusThreadManager::Get() - ->GetWilcoDtcSupportdClient() - ->BootstrapMojoConnection( - std::move(remote_endpoint_fd), - base::BindOnce(&WilcoDtcSupportdBridge::OnBootstrappedMojoConnection, - weak_ptr_factory_.GetWeakPtr())); + chromeos::WilcoDtcSupportdClient::Get()->BootstrapMojoConnection( + std::move(remote_endpoint_fd), + base::BindOnce(&WilcoDtcSupportdBridge::OnBootstrappedMojoConnection, + weak_ptr_factory_.GetWeakPtr())); } void WilcoDtcSupportdBridge::OnBootstrappedMojoConnection(bool success) {
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc index b186ae2..f91771a 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc
@@ -12,12 +12,11 @@ #include "base/optional.h" #include "base/posix/eintr_wrapper.h" #include "base/test/task_environment.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h" #include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -173,8 +172,7 @@ class WilcoDtcSupportdBridgeTest : public testing::Test { protected: WilcoDtcSupportdBridgeTest() { - DBusThreadManager::Initialize(); - CHECK(DBusThreadManager::Get()->IsUsingFakes()); + WilcoDtcSupportdClient::InitializeFake(); auto profile_manager = std::make_unique<TestingProfileManager>( TestingBrowserProcess::GetGlobal()); @@ -198,7 +196,7 @@ ~WilcoDtcSupportdBridgeTest() override { wilco_dtc_supportd_bridge_.reset(); - DBusThreadManager::Shutdown(); + WilcoDtcSupportdClient::Shutdown(); } StrictMock<MockWilcoDtcSupportdNotificationController>* @@ -212,7 +210,7 @@ FakeWilcoDtcSupportdClient* wilco_dtc_supportd_dbus_client() { WilcoDtcSupportdClient* const wilco_dtc_supportd_client = - DBusThreadManager::Get()->GetWilcoDtcSupportdClient(); + WilcoDtcSupportdClient::Get(); DCHECK(wilco_dtc_supportd_client); return static_cast<FakeWilcoDtcSupportdClient*>(wilco_dtc_supportd_client); }
diff --git a/chromeos/dbus/wilco_dtc_supportd_client.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.cc similarity index 68% rename from chromeos/dbus/wilco_dtc_supportd_client.cc rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.cc index a20ded3..6e726518 100644 --- a/chromeos/dbus/wilco_dtc_supportd_client.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.cc
@@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/dbus/wilco_dtc_supportd_client.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include <utility> #include "base/bind.h" +#include "base/feature_list.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/fake_wilco_dtc_supportd_client.h" +#include "chrome/common/chrome_features.h" #include "dbus/bus.h" #include "dbus/message.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -16,6 +19,8 @@ namespace { +WilcoDtcSupportdClient* g_instance = nullptr; + void OnVoidDBusMethod(VoidDBusMethodCallback callback, dbus::Response* response) { std::move(callback).Run(response != nullptr); @@ -32,9 +37,6 @@ WaitForServiceToBeAvailableCallback callback) override; void BootstrapMojoConnection(base::ScopedFD fd, VoidDBusMethodCallback callback) override; - - protected: - // WilcoDtcSupportdClient overrides: void Init(dbus::Bus* bus) override; private: @@ -75,11 +77,46 @@ } // namespace -// static -std::unique_ptr<WilcoDtcSupportdClient> WilcoDtcSupportdClient::Create() { - return std::make_unique<WilcoDtcSupportdClientImpl>(); +WilcoDtcSupportdClient::WilcoDtcSupportdClient() { + DCHECK(!g_instance); + g_instance = this; } -WilcoDtcSupportdClient::WilcoDtcSupportdClient() = default; +WilcoDtcSupportdClient::~WilcoDtcSupportdClient() { + DCHECK_EQ(this, g_instance); + g_instance = nullptr; +} + +// static +void WilcoDtcSupportdClient::Initialize(dbus::Bus* bus) { + DCHECK(bus); +#if defined(OS_CHROMEOS) + if (base::FeatureList::IsEnabled(::features::kWilcoDtc)) { + (new WilcoDtcSupportdClientImpl())->Init(bus); + } +#endif +} + +// static +void WilcoDtcSupportdClient::InitializeFake() { + new FakeWilcoDtcSupportdClient(); +} + +// static +void WilcoDtcSupportdClient::Shutdown() { + if (g_instance) + delete g_instance; +} + +// static +bool WilcoDtcSupportdClient::IsInitialized() { + return g_instance; +} + +// static +WilcoDtcSupportdClient* WilcoDtcSupportdClient::Get() { + CHECK(IsInitialized()); + return g_instance; +} } // namespace chromeos
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h new file mode 100644 index 0000000..98b0816 --- /dev/null +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h
@@ -0,0 +1,53 @@ +// Copyright 2018 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 CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_CLIENT_H_ +#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_CLIENT_H_ + +#include <memory> + +#include "base/component_export.h" +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "chromeos/dbus/dbus_client.h" +#include "chromeos/dbus/dbus_method_call_status.h" +#include "dbus/object_proxy.h" + +namespace chromeos { + +class WilcoDtcSupportdClient : public DBusClient { + public: + // Creates and initializes the global instance. |bus| must not be null. + static void Initialize(dbus::Bus* bus); + // Creates and initializes a fake global instance if not already created. + static void InitializeFake(); + // Destroys the global instance which must have been initialized. + static void Shutdown(); + // Checks if initialization was performed + static bool IsInitialized(); + // Returns the global instance if initialized. + static WilcoDtcSupportdClient* Get(); + + // Registers |callback| to run when the wilco_dtc_supportd service becomes + // available. + virtual void WaitForServiceToBeAvailable( + WaitForServiceToBeAvailableCallback callback) = 0; + + // Bootstrap the Mojo connection between Chrome and the wilco_dtc_supportd + // daemon. |fd| is the file descriptor with the child end of the Mojo pipe. + virtual void BootstrapMojoConnection(base::ScopedFD fd, + VoidDBusMethodCallback callback) = 0; + + protected: + // Create() should be used instead. + WilcoDtcSupportdClient(); + ~WilcoDtcSupportdClient() override; + + private: + DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdClient); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_CLIENT_H_
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc index 890e4d2e..b146978 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc
@@ -12,8 +12,8 @@ #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h" #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h" -#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/upstart/fake_upstart_client.h" #include "components/session_manager/core/session_manager.h" #include "components/session_manager/session_manager_types.h" @@ -96,11 +96,13 @@ class WilcoDtcSupportdManagerTest : public testing::Test { protected: WilcoDtcSupportdManagerTest() { - DBusThreadManager::Initialize(); + WilcoDtcSupportdClient::InitializeFake(); upstart_client_ = std::make_unique<TestUpstartClient>(); } - ~WilcoDtcSupportdManagerTest() override { DBusThreadManager::Shutdown(); } + ~WilcoDtcSupportdManagerTest() override { + WilcoDtcSupportdClient::Shutdown(); + } std::unique_ptr<WilcoDtcSupportdManager::Delegate> CreateDelegate() { return std::make_unique<FakeWilcoDtcSupportdManagerDelegate>(
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc index bba8a1d..19e2693 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc
@@ -15,9 +15,9 @@ #include "base/test/task_environment.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h" #include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h" -#include "chromeos/dbus/dbus_thread_manager.h" #include "extensions/browser/api/messaging/native_message_host.h" #include "mojo/public/cpp/system/handle.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -126,7 +126,7 @@ class WilcoDtcSupportdMessagingOpenedByExtensionTest : public testing::Test { protected: WilcoDtcSupportdMessagingOpenedByExtensionTest() { - DBusThreadManager::Initialize(); + WilcoDtcSupportdClient::InitializeFake(); testing_wilco_dtc_supportd_bridge_wrapper_ = TestingWilcoDtcSupportdBridgeWrapper::Create( &mojo_wilco_dtc_supportd_service_, @@ -140,7 +140,7 @@ // DBusThreadManager is shut down, since the WilcoDtcSupportdBridge class // uses the latter. wilco_dtc_supportd_bridge_.reset(); - DBusThreadManager::Shutdown(); + WilcoDtcSupportdClient::Shutdown(); } MockMojoWilcoDtcSupportdService* mojo_wilco_dtc_supportd_service() {
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_notification_controller_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_notification_controller_unittest.cc index 66198b0..fbd01ce 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_notification_controller_unittest.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_notification_controller_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_client.h" #include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index e15cf918..ead7d2a 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -303,12 +303,12 @@ { "name": "autofill-profile-client-validation", "owners": [ "parastoog" ], - "expiry_milestone": 77 + "expiry_milestone": 79 }, { "name": "autofill-profile-server-validation", "owners": [ "parastoog" ], - "expiry_milestone": 77 + "expiry_milestone": 79 }, { "name": "autofill-prune-suggestions", @@ -332,13 +332,13 @@ }, { "name": "autofill-use-improved-label-disambiguation", - "owners": [ "ftirelo", "tmartino" ], - "expiry_milestone": 77 + "owners": [ "fhorschig" ], + "expiry_milestone": 81 }, { "name": "autofill-use-mobile-label-disambiguation", - "owners": [ "ftirelo", "tmartino" ], - "expiry_milestone": 79 + "owners": [ "fhorschig" ], + "expiry_milestone": 81 }, { "name": "back-forward-cache", @@ -1741,8 +1741,8 @@ }, { "name": "enable-suggestions-with-substring-match", - "owners": [ "tmartino" ], - "expiry_milestone": 77 + "owners": [ "fhorschig" ], + "expiry_milestone": 81 }, { "name": "enable-surfacecontrol",
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc index f9cc8aff..afec830 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc
@@ -573,6 +573,9 @@ network_service->SetUpHttpAuth(CreateHttpAuthStaticParams(local_state_)); network_service->ConfigureHttpAuthPrefs( CreateHttpAuthDynamicParams(local_state_)); + network_service->SetSplitAuthCacheByNetworkIsolationKey( + base::FeatureList::IsEnabled( + features::kSplitAuthCacheByNetworkIsolationKey)); // TODO(lukasza): https://crbug.com/944162: Once // kMimeHandlerViewInCrossProcessFrame feature ships, unconditionally include
diff --git a/chrome/browser/offline_pages/offline_page_utils_unittest.cc b/chrome/browser/offline_pages/offline_page_utils_unittest.cc index 1e42d6e..7daf029 100644 --- a/chrome/browser/offline_pages/offline_page_utils_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_utils_unittest.cc
@@ -13,8 +13,11 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/optional.h" #include "base/run_loop.h" #include "base/strings/string16.h" +#include "base/task/post_task.h" +#include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/threading/thread_task_runner_handle.h" @@ -45,7 +48,6 @@ #include "url/gurl.h" #if defined(OS_ANDROID) -#include "base/test/bind_test_util.h" #include "base/test/test_timeouts.h" #include "chrome/browser/download/android/mock_download_controller.h" #include "components/gcm_driver/instance_id/instance_id_android.h" @@ -65,21 +67,12 @@ const char* kTestPage3ClientId = "7890"; const char* kTestPage4ClientId = "42"; -void CheckDuplicateDownloadsCallback( - OfflinePageUtils::DuplicateCheckResult* out_result, - OfflinePageUtils::DuplicateCheckResult result) { - DCHECK(out_result); - *out_result = result; +void RunTasksForDuration(base::TimeDelta delta) { + base::RunLoop run_loop; + base::PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), delta); + run_loop.Run(); } -void GetAllRequestsCallback( - std::vector<std::unique_ptr<SavePageRequest>>* out_requests, - std::vector<std::unique_ptr<SavePageRequest>> requests) { - *out_requests = std::move(requests); -} - -void SavePageLaterCallback(AddRequestResult ignored) {} - } // namespace class OfflinePageUtilsTest @@ -92,7 +85,6 @@ void SetUp() override; void TearDown() override; - void RunUntilIdle(); void SavePage(const GURL& url, const ClientId& client_id, @@ -102,24 +94,78 @@ int FindRequestByNamespaceAndURL(const std::string& name_space, const GURL& url); - // Necessary callbacks for the offline page model. - void OnSavePageDone(SavePageResult result, int64_t offlineId); - void OnClearAllDone(); - void OnExpirePageDone(bool success); - void OnGetURLDone(const GURL& url); - void OnSizeInBytesCalculated(int64_t size); + size_t GetRequestCount() { return GetAllRequests().size(); } + + // Wait until there are at least |min_request_count| requests. + void WaitForRequestMinCount(size_t min_request_count) { + for (;;) { + if (min_request_count <= GetRequestCount()) { + break; + } + RunTasksForDuration(base::TimeDelta::FromMilliseconds(100)); + } + } + + RequestCoordinator* GetRequestCoordinator() { + return RequestCoordinatorFactory::GetForBrowserContext(profile()); + } + + OfflinePageUtils::DuplicateCheckResult CheckDuplicateDownloads(GURL url) { + OfflinePageUtils::DuplicateCheckResult result; + base::RunLoop run_loop; + auto quit = run_loop.QuitClosure(); + auto on_done = [&](OfflinePageUtils::DuplicateCheckResult check_result) { + result = check_result; + quit.Run(); + }; + OfflinePageUtils::CheckDuplicateDownloads( + profile(), url, base::BindLambdaForTesting(on_done)); + + run_loop.Run(); + return result; + } + + base::Optional<int64_t> GetCachedOfflinePageSizeBetween( + const base::Time& begin_time, + const base::Time& end_time) { + int64_t result; + base::RunLoop run_loop; + auto quit = run_loop.QuitClosure(); + auto on_done = [&](int64_t size) { + result = size; + quit.Run(); + }; + if (!OfflinePageUtils::GetCachedOfflinePageSizeBetween( + profile(), base::BindLambdaForTesting(on_done), begin_time, + end_time)) { + return base::nullopt; + } + run_loop.Run(); + return result; + } // OfflinePageTestArchiver::Observer implementation: - void SetLastPathCreatedByArchiver(const base::FilePath& file_path) override; + void SetLastPathCreatedByArchiver(const base::FilePath& file_path) override {} TestScopedOfflineClock* clock() { return &clock_; } TestingProfile* profile() { return &profile_; } content::WebContents* web_contents() const { return web_contents_.get(); } - int64_t offline_id() const { return offline_id_; } - int64_t last_cache_size() { return last_cache_size_; } - void CreateCachedOfflinePages(); + std::vector<std::unique_ptr<SavePageRequest>> GetAllRequests() { + base::RunLoop run_loop; + auto quit = run_loop.QuitClosure(); + std::vector<std::unique_ptr<SavePageRequest>> result; + auto on_done = [&](std::vector<std::unique_ptr<SavePageRequest>> requests) { + result = std::move(requests); + quit.Run(); + }; + + GetRequestCoordinator()->GetAllRequests( + base::BindLambdaForTesting(on_done)); + run_loop.Run(); + return result; + } private: void CreateOfflinePages(); @@ -130,12 +176,9 @@ TestScopedOfflineClock clock_; content::BrowserTaskEnvironment task_environment_; - int64_t offline_id_; - GURL url_; TestingProfile profile_; std::unique_ptr<content::WebContents> web_contents_; base::test::ScopedFeatureList scoped_feature_list_; - int64_t last_cache_size_; #if defined(OS_ANDROID) chrome::android::MockDownloadController download_controller_; // OfflinePageTabHelper instantiates PrefetchService which in turn requests a @@ -159,7 +202,6 @@ web_contents_ = content::WebContents::Create( content::WebContents::CreateParams(profile())); OfflinePageTabHelper::CreateForWebContents(web_contents_.get()); - // Reset the value of the test clock. clock_.SetNow(base::Time::Now()); @@ -167,14 +209,14 @@ OfflinePageModelFactory::GetInstance()->SetTestingFactoryAndUse( profile_.GetProfileKey(), base::BindRepeating(&BuildTestOfflinePageModel)); - RunUntilIdle(); RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse( &profile_, base::BindRepeating(&BuildTestRequestCoordinator)); - RunUntilIdle(); // Make sure to create offline pages and requests. CreateOfflinePages(); + // TODO(harringtond): I was surprised this test creates requests in Setup(), + // we should avoid this to be less surprising. CreateRequests(); // This is needed in order to skip the logic to request storage permission. @@ -189,10 +231,6 @@ #endif } -void OfflinePageUtilsTest::RunUntilIdle() { - base::RunLoop().RunUntilIdle(); -} - void OfflinePageUtilsTest::SavePage( const GURL& url, const ClientId& client_id, @@ -200,36 +238,16 @@ OfflinePageModel::SavePageParams save_page_params; save_page_params.url = url; save_page_params.client_id = client_id; + base::RunLoop run_loop; + auto save_page_done = [&](SavePageResult result, int64_t offline_id) { + run_loop.QuitClosure().Run(); + }; OfflinePageModelFactory::GetForBrowserContext(profile())->SavePage( save_page_params, std::move(archiver), web_contents_.get(), - base::Bind(&OfflinePageUtilsTest::OnSavePageDone, AsWeakPtr())); - RunUntilIdle(); + base::BindLambdaForTesting(save_page_done)); + run_loop.Run(); } -void OfflinePageUtilsTest::OnSavePageDone(SavePageResult result, - int64_t offline_id) { - offline_id_ = offline_id; -} - -void OfflinePageUtilsTest::OnExpirePageDone(bool success) { - // Result ignored here. -} - -void OfflinePageUtilsTest::OnClearAllDone() { - // Result ignored here. -} - -void OfflinePageUtilsTest::OnGetURLDone(const GURL& url) { - url_ = url; -} - -void OfflinePageUtilsTest::OnSizeInBytesCalculated(int64_t size) { - last_cache_size_ = size; -} - -void OfflinePageUtilsTest::SetLastPathCreatedByArchiver( - const base::FilePath& file_path) {} - void OfflinePageUtilsTest::CreateOfflinePages() { // Create page 1. std::unique_ptr<OfflinePageTestArchiver> archiver(BuildArchiver( @@ -247,16 +265,16 @@ } void OfflinePageUtilsTest::CreateRequests() { - RequestCoordinator* request_coordinator = - RequestCoordinatorFactory::GetForBrowserContext(profile()); - RequestCoordinator::SavePageLaterParams params; params.url = kTestPage3Url; params.client_id = offline_pages::ClientId(kDownloadNamespace, kTestPage3ClientId); - request_coordinator->SavePageLater(params, - base::Bind(&SavePageLaterCallback)); - RunUntilIdle(); + base::RunLoop run_loop; + auto quit = run_loop.QuitClosure(); + auto page_saved = [&](AddRequestResult ignored) { quit.Run(); }; + GetRequestCoordinator()->SavePageLater( + params, base::BindLambdaForTesting(page_saved)); + run_loop.Run(); } void OfflinePageUtilsTest::CreateCachedOfflinePages() { @@ -308,12 +326,7 @@ int OfflinePageUtilsTest::FindRequestByNamespaceAndURL( const std::string& name_space, const GURL& url) { - RequestCoordinator* request_coordinator = - RequestCoordinatorFactory::GetForBrowserContext(profile()); - std::vector<std::unique_ptr<SavePageRequest>> requests; - request_coordinator->GetAllRequests( - base::Bind(&GetAllRequestsCallback, base::Unretained(&requests))); - RunUntilIdle(); + std::vector<std::unique_ptr<SavePageRequest>> requests = GetAllRequests(); int matches = 0; for (auto& request : requests) { @@ -326,31 +339,17 @@ } TEST_F(OfflinePageUtilsTest, CheckDuplicateDownloads) { - OfflinePageUtils::DuplicateCheckResult result = - OfflinePageUtils::DuplicateCheckResult::NOT_FOUND; - // The duplicate page should be found for this. - OfflinePageUtils::CheckDuplicateDownloads( - profile(), kTestPage1Url, - base::Bind(&CheckDuplicateDownloadsCallback, base::Unretained(&result))); - RunUntilIdle(); EXPECT_EQ(OfflinePageUtils::DuplicateCheckResult::DUPLICATE_PAGE_FOUND, - result); + CheckDuplicateDownloads(kTestPage1Url)); // The duplicate request should be found for this. - OfflinePageUtils::CheckDuplicateDownloads( - profile(), kTestPage3Url, - base::Bind(&CheckDuplicateDownloadsCallback, base::Unretained(&result))); - RunUntilIdle(); EXPECT_EQ(OfflinePageUtils::DuplicateCheckResult::DUPLICATE_REQUEST_FOUND, - result); + CheckDuplicateDownloads(kTestPage3Url)); // No duplicate should be found for this. - OfflinePageUtils::CheckDuplicateDownloads( - profile(), kTestPage4Url, - base::Bind(&CheckDuplicateDownloadsCallback, base::Unretained(&result))); - RunUntilIdle(); - EXPECT_EQ(OfflinePageUtils::DuplicateCheckResult::NOT_FOUND, result); + EXPECT_EQ(OfflinePageUtils::DuplicateCheckResult::NOT_FOUND, + CheckDuplicateDownloads(kTestPage4Url)); } TEST_F(OfflinePageUtilsTest, ScheduleDownload) { @@ -359,25 +358,27 @@ ASSERT_EQ(1, FindRequestByNamespaceAndURL(kDownloadNamespace, kTestPage3Url)); ASSERT_EQ(0, FindRequestByNamespaceAndURL(kDownloadNamespace, kTestPage4Url)); + // TODO(harringtond): Remove request creation in Setup(). + size_t request_count_wait = 1; // Re-downloading a page with duplicate page found. OfflinePageUtils::ScheduleDownload( web_contents(), kDownloadNamespace, kTestPage1Url, OfflinePageUtils::DownloadUIActionFlags::NONE); - RunUntilIdle(); + WaitForRequestMinCount(++request_count_wait); EXPECT_EQ(1, FindRequestByNamespaceAndURL(kDownloadNamespace, kTestPage1Url)); // Re-downloading a page with duplicate request found. OfflinePageUtils::ScheduleDownload( web_contents(), kDownloadNamespace, kTestPage3Url, OfflinePageUtils::DownloadUIActionFlags::NONE); - RunUntilIdle(); + WaitForRequestMinCount(++request_count_wait); EXPECT_EQ(2, FindRequestByNamespaceAndURL(kDownloadNamespace, kTestPage3Url)); // Downloading a page with no duplicate found. OfflinePageUtils::ScheduleDownload( web_contents(), kDownloadNamespace, kTestPage4Url, OfflinePageUtils::DownloadUIActionFlags::NONE); - RunUntilIdle(); + WaitForRequestMinCount(++request_count_wait); EXPECT_EQ(1, FindRequestByNamespaceAndURL(kDownloadNamespace, kTestPage4Url)); } @@ -387,7 +388,12 @@ OfflinePageUtils::ScheduleDownload( web_contents(), kDownloadNamespace, kTestPage4Url, OfflinePageUtils::DownloadUIActionFlags::NONE); - RunUntilIdle(); + + // Here, we're waiting to make sure a request is not created. We can't use + // QuitClosure, since there's no callback threaded through ScheduleDownload. + // Instead, just wait a bit and assume ScheduleDownload is complete. + RunTasksForDuration(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(0, FindRequestByNamespaceAndURL(kDownloadNamespace, kTestPage4Url)); } #endif @@ -400,13 +406,10 @@ clock()->Advance(base::TimeDelta::FromMinutes(5)); // Get the size of cached offline pages between 01:05:00 and 03:05:00. - bool ret = OfflinePageUtils::GetCachedOfflinePageSizeBetween( - profile(), - base::Bind(&OfflinePageUtilsTest::OnSizeInBytesCalculated, AsWeakPtr()), - clock()->Now() - base::TimeDelta::FromHours(2), clock()->Now()); - RunUntilIdle(); - EXPECT_TRUE(ret); - EXPECT_EQ(kTestFileSize * 2, last_cache_size()); + EXPECT_EQ( + kTestFileSize * 2, + GetCachedOfflinePageSizeBetween( + clock()->Now() - base::TimeDelta::FromHours(2), clock()->Now())); } TEST_F(OfflinePageUtilsTest, TestGetCachedOfflinePageSizeNoPageInModel) { @@ -423,13 +426,9 @@ // Get the size of cached offline pages between 01:00:00 and 03:00:00. // Since no temporary pages were added to the model, the cache size should be // 0. - bool ret = OfflinePageUtils::GetCachedOfflinePageSizeBetween( - profile(), - base::Bind(&OfflinePageUtilsTest::OnSizeInBytesCalculated, AsWeakPtr()), - clock()->Now() - base::TimeDelta::FromHours(2), clock()->Now()); - RunUntilIdle(); - EXPECT_TRUE(ret); - EXPECT_EQ(0, last_cache_size()); + EXPECT_EQ( + 0, GetCachedOfflinePageSizeBetween( + clock()->Now() - base::TimeDelta::FromHours(2), clock()->Now())); } TEST_F(OfflinePageUtilsTest, TestGetCachedOfflinePageSizeNoPageInRange) { @@ -440,13 +439,9 @@ clock()->Advance(base::TimeDelta::FromMinutes(5)); // Get the size of cached offline pages between 03:04:00 and 03:05:00. - bool ret = OfflinePageUtils::GetCachedOfflinePageSizeBetween( - profile(), - base::Bind(&OfflinePageUtilsTest::OnSizeInBytesCalculated, AsWeakPtr()), - clock()->Now() - base::TimeDelta::FromMinutes(1), clock()->Now()); - RunUntilIdle(); - EXPECT_TRUE(ret); - EXPECT_EQ(0, last_cache_size()); + EXPECT_EQ( + 0, GetCachedOfflinePageSizeBetween( + clock()->Now() - base::TimeDelta::FromMinutes(1), clock()->Now())); } TEST_F(OfflinePageUtilsTest, TestGetCachedOfflinePageSizeAllPagesInRange) { @@ -457,13 +452,10 @@ clock()->Advance(base::TimeDelta::FromHours(20)); // Get the size of cached offline pages between -01:00:00 and 23:00:00. - bool ret = OfflinePageUtils::GetCachedOfflinePageSizeBetween( - profile(), - base::Bind(&OfflinePageUtilsTest::OnSizeInBytesCalculated, AsWeakPtr()), - clock()->Now() - base::TimeDelta::FromHours(24), clock()->Now()); - RunUntilIdle(); - EXPECT_TRUE(ret); - EXPECT_EQ(kTestFileSize * 4, last_cache_size()); + EXPECT_EQ( + kTestFileSize * 4, + GetCachedOfflinePageSizeBetween( + clock()->Now() - base::TimeDelta::FromHours(24), clock()->Now())); } TEST_F(OfflinePageUtilsTest, TestGetCachedOfflinePageSizeAllPagesInvalidRange) { @@ -476,12 +468,8 @@ // Get the size of cached offline pages between 23:00:00 and -01:00:00, which // is an invalid range, the return value will be false and there will be no // callback. - bool ret = OfflinePageUtils::GetCachedOfflinePageSizeBetween( - profile(), - base::Bind(&OfflinePageUtilsTest::OnSizeInBytesCalculated, AsWeakPtr()), - clock()->Now(), clock()->Now() - base::TimeDelta::FromHours(24)); - RunUntilIdle(); - EXPECT_FALSE(ret); + EXPECT_FALSE(GetCachedOfflinePageSizeBetween( + clock()->Now(), clock()->Now() - base::TimeDelta::FromHours(24))); } TEST_F(OfflinePageUtilsTest, TestGetCachedOfflinePageSizeEdgeCase) { @@ -491,13 +479,10 @@ // Get the size of cached offline pages between 02:00:00 and 03:00:00, since // we are using a [begin_time, end_time) range so there will be only 1 page // when query for this time range. - bool ret = OfflinePageUtils::GetCachedOfflinePageSizeBetween( - profile(), - base::Bind(&OfflinePageUtilsTest::OnSizeInBytesCalculated, AsWeakPtr()), - clock()->Now() - base::TimeDelta::FromHours(1), clock()->Now()); - RunUntilIdle(); - EXPECT_TRUE(ret); - EXPECT_EQ(kTestFileSize * 1, last_cache_size()); + EXPECT_EQ( + kTestFileSize * 1, + GetCachedOfflinePageSizeBetween( + clock()->Now() - base::TimeDelta::FromHours(1), clock()->Now())); } // Timeout on Android. http://crbug.com/981972
diff --git a/chrome/browser/password_manager/account_storage/account_password_store_factory.cc b/chrome/browser/password_manager/account_storage/account_password_store_factory.cc index 56832b7..2f8df20 100644 --- a/chrome/browser/password_manager/account_storage/account_password_store_factory.cc +++ b/chrome/browser/password_manager/account_storage/account_password_store_factory.cc
@@ -28,8 +28,50 @@ #include "content/public/browser/network_service_instance.h" #include "content/public/browser/storage_partition.h" +#if !defined(OS_ANDROID) +#include "base/task/post_task.h" +#include "base/task/task_traits.h" +#include "chrome/browser/password_manager/chrome_password_manager_client.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/browser/browser_task_traits.h" +#endif // !defined(OS_ANDROID) + using password_manager::PasswordStore; +#if !defined(OS_ANDROID) + +namespace { + +void UpdateAllFormManagers(Profile* profile) { + for (Browser* browser : *BrowserList::GetInstance()) { + if (browser->profile() != profile) + continue; + TabStripModel* tabs = browser->tab_strip_model(); + for (int index = 0; index < tabs->count(); index++) { + content::WebContents* web_contents = tabs->GetWebContentsAt(index); + ChromePasswordManagerClient* client = + ChromePasswordManagerClient::FromWebContents(web_contents); + if (client) + client->UpdateFormManagers(); + } + } +} + +} // namespace + +#endif // !defined(OS_ANDROID) + +void SyncEnabledOrDisabled(Profile* profile) { +#if defined(OS_ANDROID) + NOTREACHED(); +#else + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&UpdateAllFormManagers, profile)); +#endif // defined(OS_ANDROID) +} + // static scoped_refptr<PasswordStore> AccountPasswordStoreFactory::GetForProfile( Profile* profile, @@ -77,7 +119,8 @@ scoped_refptr<PasswordStore> ps = new password_manager::PasswordStoreDefault(std::move(login_db)); - if (!ps->Init(/*flare=*/base::DoNothing(), profile->GetPrefs())) { + if (!ps->Init(/*flare=*/base::DoNothing(), profile->GetPrefs(), + base::BindRepeating(&SyncEnabledOrDisabled, profile))) { // TODO(crbug.com/479725): Remove the LOG once this error is visible in the // UI. LOG(WARNING) << "Could not initialize password store.";
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index e2fd2e7..835535e 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/password_manager/account_storage/account_password_store_factory.h" #include "chrome/browser/password_manager/password_store_factory.h" -#include "chrome/browser/password_manager/touch_to_fill_controller.h" #include "chrome/browser/prerender/prerender_contents.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" @@ -865,8 +864,9 @@ password_generation_driver_bindings_.GetCurrentTargetFrame(), bounds)); autofill::password_generation::PasswordGenerationUIData ui_data( - bounds, 0 /*max_length*/, base::string16() /*generation_element*/, - field_renderer_id, base::i18n::TextDirection(), form); + bounds, /*max_length=*/0, /*generation_element=*/base::string16(), + field_renderer_id, /*is_generation_element_password_type=*/true, + base::i18n::TextDirection(), form); popup_controller_ = PasswordGenerationPopupControllerImpl::GetOrCreate( popup_controller_, element_bounds_in_screen_space, ui_data, driver->AsWeakPtr(), observer_, web_contents(), @@ -1171,10 +1171,13 @@ bool is_manually_triggered) { gfx::RectF element_bounds_in_top_frame_space = TransformToRootCoordinates(driver->render_frame_host(), ui_data.bounds); + // Only show password suggestions iff the field is of password type. + bool show_password_suggestions = ui_data.is_generation_element_password_type; if (!is_manually_triggered && driver->GetPasswordAutofillManager() ->MaybeShowPasswordSuggestionsWithGeneration( - element_bounds_in_top_frame_space, ui_data.text_direction)) { + element_bounds_in_top_frame_space, ui_data.text_direction, + show_password_suggestions)) { return; }
diff --git a/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.cc b/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.cc index db8bbb34..30de8bb4 100644 --- a/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.cc +++ b/chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.cc
@@ -152,11 +152,13 @@ const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_PROFILE_CREATED: { - // TODO(1013168): Create the worker watchers here. + Profile* profile = content::Source<Profile>(source).ptr(); + CreateSharedWorkerWatcher(profile); break; } case chrome::NOTIFICATION_PROFILE_DESTROYED: { - // TODO(1013168): Delete the worker watchers here. + Profile* profile = content::Source<Profile>(source).ptr(); + DeleteSharedWorkerWatcher(profile); break; } default:
diff --git a/chrome/browser/prefs/synced_pref_change_registrar_browsertest.cc b/chrome/browser/prefs/synced_pref_change_registrar_browsertest.cc deleted file mode 100644 index a0624c1..0000000 --- a/chrome/browser/prefs/synced_pref_change_registrar_browsertest.cc +++ /dev/null
@@ -1,205 +0,0 @@ -// Copyright 2013 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 <memory> -#include <string> - -#include "base/bind.h" -#include "base/json/json_string_value_serializer.h" -#include "base/message_loop/message_loop_current.h" -#include "base/run_loop.h" -#include "base/time/time.h" -#include "base/values.h" -#include "chrome/browser/prefs/pref_service_syncable_util.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/common/pref_names.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/testing_profile.h" -#include "components/policy/core/browser/browser_policy_connector.h" -#include "components/policy/core/common/mock_configuration_policy_provider.h" -#include "components/policy/core/common/policy_map.h" -#include "components/policy/core/common/policy_types.h" -#include "components/policy/policy_constants.h" -#include "components/sync/model/fake_sync_change_processor.h" -#include "components/sync/model/sync_change.h" -#include "components/sync/model/sync_error_factory.h" -#include "components/sync/model/sync_error_factory_mock.h" -#include "components/sync/model/syncable_service.h" -#include "components/sync/protocol/sync.pb.h" -#include "components/sync_preferences/synced_pref_change_registrar.h" -#include "components/sync_preferences/testing_pref_service_syncable.h" -#include "content/public/test/test_utils.h" - -namespace { - -using testing::Return; -using testing::_; - -class SyncedPrefChangeRegistrarTest : public InProcessBrowserTest { - public: - SyncedPrefChangeRegistrarTest() : next_sync_data_id_(0) {} - ~SyncedPrefChangeRegistrarTest() override {} - - void UpdateChromePolicy(const policy::PolicyMap& policies) { - policy_provider_.UpdateChromePolicy(policies); - DCHECK(base::MessageLoopCurrent::Get()); - base::RunLoop loop; - loop.RunUntilIdle(); - } - - void SetBooleanPrefValueFromSync(const std::string& name, bool value) { - std::string serialized_value; - JSONStringValueSerializer json(&serialized_value); - json.Serialize(base::Value(value)); - - sync_pb::EntitySpecifics specifics; - sync_pb::PreferenceSpecifics* pref_specifics = - specifics.mutable_preference(); - pref_specifics->set_name(name); - pref_specifics->set_value(serialized_value); - - syncer::SyncData change_data = - syncer::SyncData::CreateRemoteData(++next_sync_data_id_, specifics); - syncer::SyncChange change( - FROM_HERE, syncer::SyncChange::ACTION_UPDATE, change_data); - - syncer::SyncChangeList change_list; - change_list.push_back(change); - - syncer_->ProcessSyncChanges(FROM_HERE, change_list); - } - - void SetBooleanPrefValueFromLocal(const std::string& name, bool value) { - prefs_->SetBoolean(name.c_str(), value); - } - - bool GetBooleanPrefValue(const std::string& name) { - return prefs_->GetBoolean(name.c_str()); - } - - sync_preferences::PrefServiceSyncable* prefs() const { return prefs_; } - - sync_preferences::SyncedPrefChangeRegistrar* registrar() const { - return registrar_.get(); - } - - private: - void SetUpInProcessBrowserTestFixture() override { - EXPECT_CALL(policy_provider_, IsInitializationComplete(_)) - .WillRepeatedly(Return(true)); - policy::BrowserPolicyConnector::SetPolicyProviderForTesting( - &policy_provider_); - } - - void SetUpOnMainThread() override { - prefs_ = PrefServiceSyncableFromProfile(browser()->profile()); - syncer_ = prefs_->GetSyncableService(syncer::PREFERENCES); - syncer_->MergeDataAndStartSyncing( - syncer::PREFERENCES, syncer::SyncDataList(), - std::unique_ptr<syncer::SyncChangeProcessor>( - new syncer::FakeSyncChangeProcessor), - std::unique_ptr<syncer::SyncErrorFactory>( - new syncer::SyncErrorFactoryMock)); - registrar_.reset(new sync_preferences::SyncedPrefChangeRegistrar(prefs_)); - } - - void TearDownOnMainThread() override { registrar_.reset(); } - - sync_preferences::PrefServiceSyncable* prefs_; - syncer::SyncableService* syncer_; - int next_sync_data_id_; - - std::unique_ptr<sync_preferences::SyncedPrefChangeRegistrar> registrar_; - policy::MockConfigurationPolicyProvider policy_provider_; -}; - -struct TestSyncedPrefObserver { - bool last_seen_value; - bool last_update_is_from_sync; - bool has_been_notified; -}; - -void TestPrefChangeCallback(PrefService* prefs, - TestSyncedPrefObserver* observer, - const std::string& path, - bool from_sync) { - observer->last_seen_value = prefs->GetBoolean(path.c_str()); - observer->last_update_is_from_sync = from_sync; - observer->has_been_notified = true; -} - -} // namespace - -IN_PROC_BROWSER_TEST_F(SyncedPrefChangeRegistrarTest, - DifferentiateRemoteAndLocalChanges) { - TestSyncedPrefObserver observer = {}; - registrar()->Add(prefs::kShowHomeButton, - base::Bind(&TestPrefChangeCallback, prefs(), &observer)); - - EXPECT_FALSE(observer.has_been_notified); - - SetBooleanPrefValueFromSync(prefs::kShowHomeButton, true); - EXPECT_TRUE(observer.has_been_notified); - EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton)); - EXPECT_TRUE(observer.last_update_is_from_sync); - EXPECT_TRUE(observer.last_seen_value); - - observer.has_been_notified = false; - SetBooleanPrefValueFromLocal(prefs::kShowHomeButton, false); - EXPECT_TRUE(observer.has_been_notified); - EXPECT_FALSE(GetBooleanPrefValue(prefs::kShowHomeButton)); - EXPECT_FALSE(observer.last_update_is_from_sync); - EXPECT_FALSE(observer.last_seen_value); - - observer.has_been_notified = false; - SetBooleanPrefValueFromLocal(prefs::kShowHomeButton, true); - EXPECT_TRUE(observer.has_been_notified); - EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton)); - EXPECT_FALSE(observer.last_update_is_from_sync); - EXPECT_TRUE(observer.last_seen_value); - - observer.has_been_notified = false; - SetBooleanPrefValueFromSync(prefs::kShowHomeButton, false); - EXPECT_TRUE(observer.has_been_notified); - EXPECT_FALSE(GetBooleanPrefValue(prefs::kShowHomeButton)); - EXPECT_TRUE(observer.last_update_is_from_sync); - EXPECT_FALSE(observer.last_seen_value); -} - -IN_PROC_BROWSER_TEST_F(SyncedPrefChangeRegistrarTest, - IgnoreLocalChangesToManagedPrefs) { - TestSyncedPrefObserver observer = {}; - registrar()->Add(prefs::kShowHomeButton, - base::Bind(&TestPrefChangeCallback, prefs(), &observer)); - - policy::PolicyMap policies; - policies.Set(policy::key::kShowHomeButton, policy::POLICY_LEVEL_MANDATORY, - policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, - std::make_unique<base::Value>(true), nullptr); - UpdateChromePolicy(policies); - - EXPECT_TRUE(prefs()->IsManagedPreference(prefs::kShowHomeButton)); - - SetBooleanPrefValueFromLocal(prefs::kShowHomeButton, false); - EXPECT_FALSE(observer.has_been_notified); - EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton)); -} - -IN_PROC_BROWSER_TEST_F(SyncedPrefChangeRegistrarTest, - IgnoreSyncChangesToManagedPrefs) { - TestSyncedPrefObserver observer = {}; - registrar()->Add(prefs::kShowHomeButton, - base::Bind(&TestPrefChangeCallback, prefs(), &observer)); - - policy::PolicyMap policies; - policies.Set(policy::key::kShowHomeButton, policy::POLICY_LEVEL_MANDATORY, - policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, - std::make_unique<base::Value>(true), nullptr); - UpdateChromePolicy(policies); - - EXPECT_TRUE(prefs()->IsManagedPreference(prefs::kShowHomeButton)); - SetBooleanPrefValueFromSync(prefs::kShowHomeButton, false); - EXPECT_FALSE(observer.has_been_notified); - EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton)); -}
diff --git a/chrome/browser/profiles/gaia_info_update_service_unittest.cc b/chrome/browser/profiles/gaia_info_update_service_unittest.cc index 9156a3d..242e148 100644 --- a/chrome/browser/profiles/gaia_info_update_service_unittest.cc +++ b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
@@ -294,48 +294,6 @@ GetString(prefs::kGoogleServicesHostedDomain)); } -// TODO(anthonyvd) : remove or update test once the refactoring of the internals -// of ProfileInfoCache is complete. -TEST_F(GAIAInfoUpdateServiceTest, HandlesProfileReordering) { - size_t index = GetCache()->GetIndexOfProfileWithPath(profile()->GetPath()); - GetCache()->SetLocalProfileNameOfProfileAtIndex(index, FullName16("B")); - GetCache()->SetProfileIsUsingDefaultNameAtIndex(index, true); - - CreateProfile(FullName("A")); - CreateProfile(FullName("C")); - CreateProfile(FullName("E")); - - size_t index_before = - GetCache()->GetIndexOfProfileWithPath(profile()->GetPath()); - - // Rename our profile. - RenameProfile(FullName16("D"), GivenName16("D")); - // Profiles should have been reordered in the cache. - EXPECT_NE(index_before, - GetCache()->GetIndexOfProfileWithPath(profile()->GetPath())); - // Rename the profile back to the original name, it should go back to its - // original position. - RenameProfile(FullName16("B"), GivenName16("B")); - EXPECT_EQ(index_before, - GetCache()->GetIndexOfProfileWithPath(profile()->GetPath())); - - // Rename only the given name of our profile. - RenameProfile(FullName16("B"), GivenName16("D")); - // Rename the profile back to the original name, it should go back to its - // original position. - RenameProfile(FullName16("B"), GivenName16("B")); - EXPECT_EQ(index_before, - GetCache()->GetIndexOfProfileWithPath(profile()->GetPath())); - - // Rename only the full name of our profile. - RenameProfile(FullName16("D"), GivenName16("B")); - // Rename the profile back to the original name, it should go back to its - // original position. - RenameProfile(FullName16("B"), GivenName16("B")); - EXPECT_EQ(index_before, - GetCache()->GetIndexOfProfileWithPath(profile()->GetPath())); -} - TEST_F(GAIAInfoUpdateServiceTest, ShouldUseGAIAProfileInfo) { #if defined(OS_CHROMEOS) // This feature should never be enabled on ChromeOS.
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc index 3945acf3..75cd830 100644 --- a/chrome/browser/profiles/profile_info_cache.cc +++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -83,7 +83,7 @@ #endif base::string16 name; info->GetString(kNameKey, &name); - sorted_keys_.insert(FindPositionForProfile(it.key(), name), it.key()); + keys_.push_back(it.key()); profile_attributes_entries_[user_data_dir_.AppendASCII(it.key()).value()] = std::unique_ptr<ProfileAttributesEntry>(nullptr); @@ -167,7 +167,7 @@ old_single_profile_name = entry->GetName(); } - sorted_keys_.insert(FindPositionForProfile(key, name), key); + keys_.push_back(key); profile_attributes_entries_[user_data_dir_.AppendASCII(key).value()] = std::unique_ptr<ProfileAttributesEntry>(); @@ -219,7 +219,7 @@ base::DictionaryValue* cache = update.Get(); std::string key = CacheKeyFromProfilePath(profile_path); cache->Remove(key, NULL); - sorted_keys_.erase(std::find(sorted_keys_.begin(), sorted_keys_.end(), key)); + keys_.erase(std::find(keys_.begin(), keys_.end(), key)); profile_attributes_entries_.erase(profile_path.value()); bool single_profile_name_changed = @@ -236,7 +236,7 @@ } size_t ProfileInfoCache::GetNumberOfProfiles() const { - return sorted_keys_.size(); + return keys_.size(); } size_t ProfileInfoCache::GetIndexOfProfileWithPath( @@ -244,8 +244,8 @@ if (profile_path.DirName() != user_data_dir_) return std::string::npos; std::string search_key = CacheKeyFromProfilePath(profile_path); - for (size_t i = 0; i < sorted_keys_.size(); ++i) { - if (sorted_keys_[i] == search_key) + for (size_t i = 0; i < keys_.size(); ++i) { + if (keys_[i] == search_key) return i; } return std::string::npos; @@ -279,7 +279,7 @@ } base::FilePath ProfileInfoCache::GetPathOfProfileAtIndex(size_t index) const { - return user_data_dir_.AppendASCII(sorted_keys_[index]); + return user_data_dir_.AppendASCII(keys_[index]); } base::string16 ProfileInfoCache::GetUserNameOfProfileAtIndex( @@ -455,7 +455,6 @@ base::string16 new_display_name = GetNameToDisplayOfProfileAtIndex(index); base::FilePath profile_path = GetPathOfProfileAtIndex(index); - UpdateSortForProfileIndex(index); if (old_display_name != new_display_name) { for (auto& observer : observer_list_) @@ -572,7 +571,6 @@ SetInfoForProfileAtIndex(index, std::move(info)); base::string16 new_display_name = GetNameToDisplayOfProfileAtIndex(index); base::FilePath profile_path = GetPathOfProfileAtIndex(index); - UpdateSortForProfileIndex(index); if (old_display_name != new_display_name) { for (auto& observer : observer_list_) @@ -593,7 +591,6 @@ SetInfoForProfileAtIndex(index, std::move(info)); base::string16 new_display_name = GetNameToDisplayOfProfileAtIndex(index); base::FilePath profile_path = GetPathOfProfileAtIndex(index); - UpdateSortForProfileIndex(index); if (old_display_name != new_display_name) { for (auto& observer : observer_list_) @@ -723,7 +720,7 @@ const base::DictionaryValue* cache = prefs_->GetDictionary(prefs::kProfileInfoCache); const base::DictionaryValue* info = NULL; - cache->GetDictionaryWithoutPathExpansion(sorted_keys_[index], &info); + cache->GetDictionaryWithoutPathExpansion(keys_[index], &info); return info; } @@ -732,7 +729,7 @@ std::unique_ptr<base::DictionaryValue> info) { DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache); base::DictionaryValue* cache = update.Get(); - cache->SetWithoutPathExpansion(sorted_keys_[index], std::move(info)); + cache->SetWithoutPathExpansion(keys_[index], std::move(info)); } std::string ProfileInfoCache::CacheKeyFromProfilePath( @@ -742,36 +739,6 @@ return base_name.MaybeAsASCII(); } -std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile( - const std::string& search_key, - const base::string16& search_name) { - base::string16 search_name_l = base::i18n::ToLower(search_name); - for (size_t i = 0; i < GetNumberOfProfiles(); ++i) { - base::string16 name_l = - base::i18n::ToLower(GetNameToDisplayOfProfileAtIndex(i)); - int name_compare = search_name_l.compare(name_l); - if (name_compare < 0) - return sorted_keys_.begin() + i; - if (name_compare == 0) { - int key_compare = search_key.compare(sorted_keys_[i]); - if (key_compare < 0) - return sorted_keys_.begin() + i; - } - } - return sorted_keys_.end(); -} - -void ProfileInfoCache::UpdateSortForProfileIndex(size_t index) { - base::string16 name = GetNameToDisplayOfProfileAtIndex(index); - - // Remove and reinsert key in |sorted_keys_| to alphasort. - std::string key = CacheKeyFromProfilePath(GetPathOfProfileAtIndex(index)); - auto key_it = std::find(sorted_keys_.begin(), sorted_keys_.end(), key); - DCHECK(key_it != sorted_keys_.end()); - sorted_keys_.erase(key_it); - sorted_keys_.insert(FindPositionForProfile(key, name), key); -} - const gfx::Image* ProfileInfoCache::GetHighResAvatarOfProfileAtIndex( size_t index) const { const size_t avatar_index = GetAvatarIconIndexOfProfileAtIndex(index); @@ -806,7 +773,6 @@ if (name == entries[j]->GetLocalProfileName()) { entries[j]->SetLocalProfileName( ChooseNameForNewProfile(entries[j]->GetAvatarIconIndex())); - UpdateSortForProfileIndex(entries[j]->profile_index()); } } }
diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h index c7b2632..3e5ed91 100644 --- a/chrome/browser/profiles/profile_info_cache.h +++ b/chrome/browser/profiles/profile_info_cache.h
@@ -197,7 +197,7 @@ // recomputed to "Person 1" and "Person 2". void RecomputeProfileNamesIfNeeded(); - std::vector<std::string> sorted_keys_; + std::vector<std::string> keys_; const base::FilePath user_data_dir_; DISALLOW_COPY_AND_ASSIGN(ProfileInfoCache);
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc index 6d91c2d..7d99272 100644 --- a/chrome/browser/profiles/profile_info_cache_unittest.cc +++ b/chrome/browser/profiles/profile_info_cache_unittest.cc
@@ -281,12 +281,9 @@ EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(index1).empty()); EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(index2).empty()); - // Set GAIA name. This re-sorts the cache. + // Set GAIA name. base::string16 gaia_name(ASCIIToUTF16("Pat Smith")); GetCache()->SetGAIANameOfProfileAtIndex(index2, gaia_name); - index1 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_1")); - index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2")); - // Since there is a GAIA name, we use that as a display name. EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(index1).empty()); EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(index2)); @@ -294,14 +291,10 @@ concatenate_enabled_, false), GetCache()->GetNameToDisplayOfProfileAtIndex(index2)); - // This re-sorts the cache. base::string16 custom_name(ASCIIToUTF16("Custom name")); GetCache()->SetLocalProfileNameOfProfileAtIndex(index2, custom_name); GetCache()->SetProfileIsUsingDefaultNameAtIndex(index2, false); - index1 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_1")); - index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2")); - EXPECT_EQ(GetExpectedNameToDisplay(gaia_name, custom_name, false, concatenate_enabled_, false), GetCache()->GetNameToDisplayOfProfileAtIndex(index2)); @@ -331,7 +324,6 @@ GetProfilePath("path_2"), ASCIIToUTF16("Person 2"), std::string(), base::string16(), false, 0, std::string(), EmptyAccountId()); - index1 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_1")); EXPECT_EQ(ASCIIToUTF16("Patt (Person 1)"), GetCache()->GetNameToDisplayOfProfileAtIndex(index1)); @@ -340,16 +332,13 @@ GetCache()->GetNameToDisplayOfProfileAtIndex(index2)); // Set Gaia name. GetCache()->SetGAIANameOfProfileAtIndex(index2, ASCIIToUTF16("Patti Smith")); - index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2")); // Profile name is a substring of Gaia name. GetCache()->SetLocalProfileNameOfProfileAtIndex(index2, ASCIIToUTF16("patti")); - index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2")); EXPECT_EQ(ASCIIToUTF16("Patti Smith"), GetCache()->GetNameToDisplayOfProfileAtIndex(index2)); // Profile name equals Gaia given name. GetCache()->SetGAIAGivenNameOfProfileAtIndex(index2, ASCIIToUTF16("Patti")); - index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2")); EXPECT_EQ(ASCIIToUTF16("Patti"), GetCache()->GetNameToDisplayOfProfileAtIndex(index2)); GetCache()->SetLocalProfileNameOfProfileAtIndex(index2, ASCIIToUTF16("Work")); @@ -362,12 +351,10 @@ std::string(), EmptyAccountId()); int index3 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_3")); GetCache()->SetGAIAGivenNameOfProfileAtIndex(index3, ASCIIToUTF16("Pat")); - index3 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_3")); EXPECT_EQ(ASCIIToUTF16("Pat"), GetCache()->GetNameToDisplayOfProfileAtIndex(index3)); GetCache()->SetGAIANameOfProfileAtIndex(index3, ASCIIToUTF16("Pat Smith")); GetCache()->SetGAIAGivenNameOfProfileAtIndex(index3, ASCIIToUTF16("")); - index3 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_3")); EXPECT_EQ(ASCIIToUTF16("Pat Smith"), GetCache()->GetNameToDisplayOfProfileAtIndex(index3)); @@ -438,49 +425,6 @@ #endif } -TEST_F(ProfileInfoCacheTest, Sort) { - base::string16 name_a = ASCIIToUTF16("apple"); - GetCache()->AddProfileToCache(GetProfilePath("path_a"), name_a, std::string(), - base::string16(), false, 0, std::string(), - EmptyAccountId()); - - base::string16 name_c = ASCIIToUTF16("cat"); - GetCache()->AddProfileToCache(GetProfilePath("path_c"), name_c, std::string(), - base::string16(), false, 0, std::string(), - EmptyAccountId()); - - // Sanity check the initial order. - EXPECT_EQ(name_a, GetCache()->GetNameToDisplayOfProfileAtIndex(0)); - EXPECT_EQ(name_c, GetCache()->GetNameToDisplayOfProfileAtIndex(1)); - - // Add a new profile (start with a capital to test case insensitive sorting. - base::string16 name_b = ASCIIToUTF16("Banana"); - GetCache()->AddProfileToCache(GetProfilePath("path_b"), name_b, std::string(), - base::string16(), false, 0, std::string(), - EmptyAccountId()); - - // Verify the new order. - EXPECT_EQ(name_a, GetCache()->GetNameToDisplayOfProfileAtIndex(0)); - EXPECT_EQ(name_b, GetCache()->GetNameToDisplayOfProfileAtIndex(1)); - EXPECT_EQ(name_c, GetCache()->GetNameToDisplayOfProfileAtIndex(2)); - - // Change the name of an existing profile. - name_a = UTF8ToUTF16("dog"); - GetCache()->SetLocalProfileNameOfProfileAtIndex(0, name_a); - - // Verify the new order. - EXPECT_EQ(name_b, GetCache()->GetNameToDisplayOfProfileAtIndex(0)); - EXPECT_EQ(name_c, GetCache()->GetNameToDisplayOfProfileAtIndex(1)); - EXPECT_EQ(name_a, GetCache()->GetNameToDisplayOfProfileAtIndex(2)); - - // Delete a profile. - GetCache()->DeleteProfileFromCache(GetProfilePath("path_c")); - - // Verify the new order. - EXPECT_EQ(name_b, GetCache()->GetNameToDisplayOfProfileAtIndex(0)); - EXPECT_EQ(name_a, GetCache()->GetNameToDisplayOfProfileAtIndex(1)); -} - // Will be removed SOON with ProfileInfoCache tests. TEST_F(ProfileInfoCacheTest, BackgroundModeStatus) { GetCache()->AddProfileToCache(
diff --git a/chrome/browser/resources/ntp4/incognito_tab.css b/chrome/browser/resources/ntp4/incognito_tab.css index 23dfea3..a5f3cbb 100644 --- a/chrome/browser/resources/ntp4/incognito_tab.css +++ b/chrome/browser/resources/ntp4/incognito_tab.css
@@ -124,6 +124,10 @@ flex: none; } +#cookie-controls-toggle:not(:defined) { + width: 34px; +} + /** Layout ------------------------------------------------------------------ */ /* Align the content, icon, and title to to the center. */
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc b/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc index 9fb4cfe..2924c05 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_browsertest.cc
@@ -28,7 +28,7 @@ namespace { const char kTelUrl[] = "tel:+9876543210"; const char kNonTelUrl[] = "https://google.com"; - +const char kLinkText[] = "Google"; const char kTextWithPhoneNumber[] = "call 9876543210 now"; const char kTextWithoutPhoneNumber[] = "abcde"; @@ -46,11 +46,6 @@ return std::string(kTestPageURL); } - void SetUpDevices(int count) { - SharingBrowserTest::SetUpDevices( - count, sync_pb::SharingSpecificFields::CLICK_TO_CALL); - } - void CheckLastSharingMessageSent( const std::string& expected_phone_number) const { chrome_browser_sharing::SharingMessage sharing_message = @@ -79,17 +74,14 @@ // TODO(himanshujaju): Add UI checks. IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_TelLink_SingleDeviceAvailable) { - Init(); - SetUpDevices(/*count=*/1); - + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::UNKNOWN); auto devices = sharing_service()->GetDeviceCandidates( sync_pb::SharingSpecificFields::CLICK_TO_CALL); - ASSERT_EQ(1u, devices.size()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithoutPhoneNumber)); + InitContextMenu(GURL(kTelUrl), kLinkText, kTextWithoutPhoneNumber); // Check click to call items in context menu ASSERT_TRUE(menu->IsItemPresent( @@ -104,12 +96,14 @@ } IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_NoDevicesAvailable) { - Init(); - AwaitQuiescence(); + Init(sync_pb::SharingSpecificFields::UNKNOWN, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::CLICK_TO_CALL); + ASSERT_EQ(0u, devices.size()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithoutPhoneNumber)); + InitContextMenu(GURL(kTelUrl), kLinkText, kTextWithoutPhoneNumber); EXPECT_FALSE(menu->IsItemPresent( IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE)); EXPECT_FALSE(menu->IsItemPresent( @@ -118,15 +112,18 @@ IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_DevicesAvailable_SyncTurnedOff) { - Init(); - SetUpDevices(/*count=*/1); + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::CLICK_TO_CALL); + ASSERT_EQ(1u, devices.size()); + // Disable syncing preferences which is necessary for Sharing. GetSyncService(0)->GetUserSettings()->SetSelectedTypes(false, {}); - AwaitQuiescence(); + ASSERT_TRUE(AwaitQuiescence()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithoutPhoneNumber)); + InitContextMenu(GURL(kTelUrl), kLinkText, kTextWithoutPhoneNumber); EXPECT_FALSE(menu->IsItemPresent( IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE)); EXPECT_FALSE(menu->IsItemPresent( @@ -135,17 +132,14 @@ IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_TelLink_MultipleDevicesAvailable) { - Init(); - SetUpDevices(/*count=*/2); - + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::CLICK_TO_CALL); auto devices = sharing_service()->GetDeviceCandidates( sync_pb::SharingSpecificFields::CLICK_TO_CALL); - ASSERT_EQ(2u, devices.size()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithoutPhoneNumber)); + InitContextMenu(GURL(kTelUrl), kLinkText, kTextWithoutPhoneNumber); EXPECT_FALSE(menu->IsItemPresent( IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE)); ASSERT_TRUE(menu->IsItemPresent( @@ -171,17 +165,14 @@ IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_HighlightedText_MultipleDevicesAvailable) { - Init(); - SetUpDevices(/*count=*/2); - + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::CLICK_TO_CALL); auto devices = sharing_service()->GetDeviceCandidates( sync_pb::SharingSpecificFields::CLICK_TO_CALL); - ASSERT_EQ(2u, devices.size()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kNonTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithPhoneNumber)); + InitContextMenu(GURL(kNonTelUrl), kLinkText, kTextWithPhoneNumber); EXPECT_FALSE(menu->IsItemPresent( IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE)); ASSERT_TRUE(menu->IsItemPresent( @@ -220,17 +211,14 @@ IN_PROC_BROWSER_TEST_F( ClickToCallBrowserTestWithContextMenuDisabled, ContextMenu_HighlightedText_DevicesAvailable_FeatureFlagOff) { - Init(); - SetUpDevices(/*count=*/2); - + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::CLICK_TO_CALL); auto devices = sharing_service()->GetDeviceCandidates( sync_pb::SharingSpecificFields::CLICK_TO_CALL); - ASSERT_EQ(2u, devices.size()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kNonTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithPhoneNumber)); + InitContextMenu(GURL(kNonTelUrl), kLinkText, kTextWithPhoneNumber); EXPECT_FALSE(menu->IsItemPresent( IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE)); @@ -239,8 +227,11 @@ } IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, ContextMenu_UKM) { - Init(); - SetUpDevices(/*count=*/1); + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::CLICK_TO_CALL); + ASSERT_EQ(1u, devices.size()); ukm::TestAutoSetUkmRecorder ukm_recorder; base::RunLoop run_loop; @@ -248,8 +239,7 @@ ukm::builders::Sharing_ClickToCall::kEntryName, run_loop.QuitClosure()); std::unique_ptr<TestRenderViewContextMenu> menu = - InitRightClickMenu(GURL(kNonTelUrl), base::ASCIIToUTF16("Google"), - base::ASCIIToUTF16(kTextWithPhoneNumber)); + InitContextMenu(GURL(kNonTelUrl), kLinkText, kTextWithPhoneNumber); // Check click to call items in context menu ASSERT_TRUE(menu->IsItemPresent( @@ -298,8 +288,11 @@ }; IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, CloseTabWithBubble) { - Init(); - SetUpDevices(/*count=*/1); + Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::CLICK_TO_CALL); + ASSERT_EQ(1u, devices.size()); base::RunLoop run_loop; ClickToCallUiController::GetOrCreateFromWebContents(web_contents())
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_browsertest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_browsertest.cc new file mode 100644 index 0000000..57b0418 --- /dev/null +++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_browsertest.cc
@@ -0,0 +1,169 @@ +// Copyright 2019 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 <memory> +#include <string> + +#include "base/macros.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" +#include "chrome/browser/sharing/shared_clipboard/feature_flags.h" +#include "chrome/browser/sharing/sharing_browsertest.h" +#include "chrome/browser/sharing/sharing_constants.h" +#include "chrome/browser/sharing/sharing_metrics.h" +#include "chrome/browser/sharing/sharing_sync_preference.h" +#include "chrome/browser/sync/test/integration/sessions_helper.h" +#include "components/sync/driver/profile_sync_service.h" +#include "url/gurl.h" + +namespace { +const char kSelectedText[] = "Lorem ipsum"; +const char kTestPageURL[] = "/sharing/tel.html"; +} // namespace + +// Browser tests for the Shared Clipboard feature. +class SharedClipboardBrowserTestBase : public SharingBrowserTest { + public: + SharedClipboardBrowserTestBase() {} + + ~SharedClipboardBrowserTestBase() override = default; + + std::string GetTestPageURL() const override { + return std::string(kTestPageURL); + } + + void CheckLastSharingMessageSent(const std::string& expected_text) const { + chrome_browser_sharing::SharingMessage sharing_message = + GetLastSharingMessageSent(); + ASSERT_TRUE(sharing_message.has_shared_clipboard_message()); + ASSERT_EQ(expected_text, sharing_message.shared_clipboard_message().text()); + } + + protected: + base::test::ScopedFeatureList feature_list_; + + private: + DISALLOW_COPY_AND_ASSIGN(SharedClipboardBrowserTestBase); +}; + +class SharedClipboardBrowserTest : public SharedClipboardBrowserTestBase { + public: + SharedClipboardBrowserTest() { + feature_list_.InitWithFeatures({kSharedClipboardUI}, {}); + } +}; + +IN_PROC_BROWSER_TEST_F(SharedClipboardBrowserTest, ContextMenu_SingleDevice) { + Init(sync_pb::SharingSpecificFields::SHARED_CLIPBOARD, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + ASSERT_EQ(1u, devices.size()); + + std::unique_ptr<TestRenderViewContextMenu> menu = + InitContextMenu(GURL(), "", kSelectedText); + ASSERT_TRUE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE)); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES)); + + menu->ExecuteCommand( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE, 0); + CheckLastReceiver(devices[0]->guid()); + CheckLastSharingMessageSent(kSelectedText); +} + +IN_PROC_BROWSER_TEST_F(SharedClipboardBrowserTest, + ContextMenu_MultipleDevices) { + Init(sync_pb::SharingSpecificFields::SHARED_CLIPBOARD, + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + ASSERT_EQ(2u, devices.size()); + + std::unique_ptr<TestRenderViewContextMenu> menu = + InitContextMenu(GURL(), "", kSelectedText); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE)); + ASSERT_TRUE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES)); + + ui::MenuModel* sub_menu_model = nullptr; + int device_id = -1; + ASSERT_TRUE(menu->GetMenuModelAndItemIndex(kSubMenuFirstDeviceCommandId, + &sub_menu_model, &device_id)); + EXPECT_EQ(2, sub_menu_model->GetItemCount()); + EXPECT_EQ(0, device_id); + + for (auto& device : devices) { + EXPECT_EQ(kSubMenuFirstDeviceCommandId + device_id, + sub_menu_model->GetCommandIdAt(device_id)); + sub_menu_model->ActivatedAt(device_id); + + CheckLastReceiver(device->guid()); + CheckLastSharingMessageSent(kSelectedText); + device_id++; + } +} + +IN_PROC_BROWSER_TEST_F(SharedClipboardBrowserTest, ContextMenu_NoDevices) { + Init(sync_pb::SharingSpecificFields::UNKNOWN, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + ASSERT_EQ(0u, devices.size()); + + std::unique_ptr<TestRenderViewContextMenu> menu = + InitContextMenu(GURL(), "", kSelectedText); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE)); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES)); +} + +IN_PROC_BROWSER_TEST_F(SharedClipboardBrowserTest, ContextMenu_SyncTurnedOff) { + Init(sync_pb::SharingSpecificFields::SHARED_CLIPBOARD, + sync_pb::SharingSpecificFields::UNKNOWN); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + ASSERT_EQ(1u, devices.size()); + + // Disable syncing preferences which is necessary for Sharing. + GetSyncService(0)->GetUserSettings()->SetSelectedTypes(false, {}); + ASSERT_TRUE(AwaitQuiescence()); + + std::unique_ptr<TestRenderViewContextMenu> menu = + InitContextMenu(GURL(), "", kSelectedText); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE)); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES)); +} + +class SharedClipboardUIFeatureDisabledBrowserTest + : public SharedClipboardBrowserTestBase { + public: + SharedClipboardUIFeatureDisabledBrowserTest() { + feature_list_.InitWithFeatures({}, {kSharedClipboardUI}); + } +}; + +IN_PROC_BROWSER_TEST_F(SharedClipboardUIFeatureDisabledBrowserTest, + ContextMenu_UIFeatureDisabled) { + Init(sync_pb::SharingSpecificFields::SHARED_CLIPBOARD, + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + auto devices = sharing_service()->GetDeviceCandidates( + sync_pb::SharingSpecificFields::SHARED_CLIPBOARD); + ASSERT_EQ(2u, devices.size()); + + std::unique_ptr<TestRenderViewContextMenu> menu = + InitContextMenu(GURL(), "", kSelectedText); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE)); + ASSERT_FALSE(menu->IsItemPresent( + IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES)); +}
diff --git a/chrome/browser/sharing/sharing_browsertest.cc b/chrome/browser/sharing/sharing_browsertest.cc index 664ce06..4e05aee 100644 --- a/chrome/browser/sharing/sharing_browsertest.cc +++ b/chrome/browser/sharing/sharing_browsertest.cc
@@ -7,6 +7,8 @@ #include "base/bind.h" #include "base/run_loop.h" #include "base/strings/strcat.h" +#include "base/strings/string_piece.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" #include "build/build_config.h" #include "chrome/app/chrome_command_ids.h" @@ -32,7 +34,9 @@ host_resolver()->AddRule("mock.http", "127.0.0.1"); } -void SharingBrowserTest::Init() { +void SharingBrowserTest::Init( + sync_pb::SharingSpecificFields_EnabledFeatures first_device_feature, + sync_pb::SharingSpecificFields_EnabledFeatures second_device_feature) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; ASSERT_TRUE(embedded_test_server()->Start()); @@ -47,67 +51,86 @@ gcm_service_->set_collect(true); sharing_service_ = SharingServiceFactory::GetForBrowserContext(GetProfile(0)); + + SetUpDevices(first_device_feature, second_device_feature); } void SharingBrowserTest::SetUpDevices( - int count, - sync_pb::SharingSpecificFields_EnabledFeatures feature) { - for (int i = 0; i < count; i++) { - SharingService* service = - SharingServiceFactory::GetForBrowserContext(GetProfile(i)); - service->SetDeviceInfoTrackerForTesting(&fake_device_info_tracker_); + sync_pb::SharingSpecificFields_EnabledFeatures first_device_feature, + sync_pb::SharingSpecificFields_EnabledFeatures second_device_feature) { + ASSERT_EQ(2u, GetSyncClients().size()); - base::RunLoop run_loop; - service->RegisterDeviceInTesting( - std::set<sync_pb::SharingSpecificFields_EnabledFeatures>{feature}, - base::BindLambdaForTesting([&](SharingDeviceRegistrationResult r) { - ASSERT_EQ(SharingDeviceRegistrationResult::kSuccess, r); - run_loop.Quit(); - })); - run_loop.Run(); - AwaitQuiescence(); - } + RegisterDevice(0, first_device_feature); + RegisterDevice(1, second_device_feature); syncer::DeviceInfoTracker* original_device_info_tracker = DeviceInfoSyncServiceFactory::GetForProfile(GetProfile(0)) ->GetDeviceInfoTracker(); std::vector<std::unique_ptr<syncer::DeviceInfo>> original_devices = original_device_info_tracker->GetAllDeviceInfo(); - int device_id = 0; + ASSERT_EQ(2u, original_devices.size()); - for (auto& device : original_devices) { - std::unique_ptr<syncer::DeviceInfo> fake_device = - std::make_unique<syncer::DeviceInfo>( - device->guid(), - base::StrCat({"testing_device_", base::NumberToString(device_id)}), - device->chrome_version(), device->sync_user_agent(), - device->device_type(), device->signin_scoped_device_id(), - base::SysInfo::HardwareInfo{ - "Google", - base::StrCat({"model", base::NumberToString(device_id)}), - "serial_number"}, - device->last_updated_timestamp(), - device->send_tab_to_self_receiving_enabled(), - device->sharing_info()); - fake_device_info_tracker_.Add(fake_device.get()); - device_infos_.push_back(std::move(fake_device)); - device_id++; - } + for (size_t i = 0; i < original_devices.size(); i++) + AddDeviceInfo(*original_devices[i], i); + ASSERT_EQ(2, fake_device_info_tracker_.CountActiveDevices()); } -// TODO(himanshujaju): try to move to static method in -// render_view_context_menu_test_util.cc -std::unique_ptr<TestRenderViewContextMenu> -SharingBrowserTest::InitRightClickMenu(const GURL& url, - const base::string16& link_text, - const base::string16& selection_text) { +void SharingBrowserTest::RegisterDevice( + int profile_index, + sync_pb::SharingSpecificFields_EnabledFeatures feature) { + SharingService* service = + SharingServiceFactory::GetForBrowserContext(GetProfile(profile_index)); + service->SetDeviceInfoTrackerForTesting(&fake_device_info_tracker_); + + base::RunLoop run_loop; + service->RegisterDeviceInTesting( + std::set<sync_pb::SharingSpecificFields_EnabledFeatures>{feature}, + base::BindLambdaForTesting([&](SharingDeviceRegistrationResult r) { + ASSERT_EQ(SharingDeviceRegistrationResult::kSuccess, r); + run_loop.Quit(); + })); + run_loop.Run(); + ASSERT_TRUE(AwaitQuiescence()); +} + +void SharingBrowserTest::AddDeviceInfo( + const syncer::DeviceInfo& original_device, + int fake_device_id) { + // The SharingInfo on the DeviceInfo will be empty. In this test we want the + // SharingInfo to be read from SharingSyncPreference instead. + base::Optional<syncer::DeviceInfo::SharingInfo> fake_sharing_info = + base::nullopt; + + std::unique_ptr<syncer::DeviceInfo> fake_device = + std::make_unique<syncer::DeviceInfo>( + original_device.guid(), + base::StrCat( + {"testing_device_", base::NumberToString(fake_device_id)}), + original_device.chrome_version(), original_device.sync_user_agent(), + original_device.device_type(), + original_device.signin_scoped_device_id(), + base::SysInfo::HardwareInfo{ + "Google", + base::StrCat({"model", base::NumberToString(fake_device_id)}), + "serial_number"}, + original_device.last_updated_timestamp(), + original_device.send_tab_to_self_receiving_enabled(), + fake_sharing_info); + fake_device_info_tracker_.Add(fake_device.get()); + device_infos_.push_back(std::move(fake_device)); +} + +std::unique_ptr<TestRenderViewContextMenu> SharingBrowserTest::InitContextMenu( + const GURL& url, + base::StringPiece link_text, + base::StringPiece selection_text) { content::ContextMenuParams params; - params.selection_text = selection_text; + params.selection_text = base::ASCIIToUTF16(selection_text); params.media_type = blink::WebContextMenuData::MediaType::kMediaTypeNone; params.unfiltered_link_url = url; params.link_url = url; params.src_url = url; - params.link_text = link_text; + params.link_text = base::ASCIIToUTF16(link_text); params.page_url = web_contents_->GetVisibleURL(); params.source_type = ui::MenuSourceType::MENU_SOURCE_MOUSE; #if defined(OS_MACOSX)
diff --git a/chrome/browser/sharing/sharing_browsertest.h b/chrome/browser/sharing/sharing_browsertest.h index 0f1d3b7a..1148070 100644 --- a/chrome/browser/sharing/sharing_browsertest.h +++ b/chrome/browser/sharing/sharing_browsertest.h
@@ -9,6 +9,7 @@ #include <string> #include "base/macros.h" +#include "base/strings/string_piece_forward.h" #include "chrome/browser/gcm/gcm_profile_service_factory.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" #include "chrome/browser/sharing/sharing_service.h" @@ -27,17 +28,16 @@ void SetUpOnMainThread() override; - void Init(); + void Init( + sync_pb::SharingSpecificFields_EnabledFeatures first_device_feature, + sync_pb::SharingSpecificFields_EnabledFeatures second_device_feature); virtual std::string GetTestPageURL() const = 0; - void SetUpDevices(int count, - sync_pb::SharingSpecificFields_EnabledFeatures feature); - - std::unique_ptr<TestRenderViewContextMenu> InitRightClickMenu( + std::unique_ptr<TestRenderViewContextMenu> InitContextMenu( const GURL& url, - const base::string16& link_text, - const base::string16& selection_text); + base::StringPiece link_text, + base::StringPiece selection_text); void CheckLastReceiver(const std::string& device_guid) const; @@ -48,6 +48,15 @@ content::WebContents* web_contents() const; private: + void SetUpDevices( + sync_pb::SharingSpecificFields_EnabledFeatures first_device_feature, + sync_pb::SharingSpecificFields_EnabledFeatures second_device_feature); + + void RegisterDevice(int profile_index, + sync_pb::SharingSpecificFields_EnabledFeatures feature); + void AddDeviceInfo(const syncer::DeviceInfo& original_device, + int fake_device_id); + gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller scoped_testing_factory_installer_; gcm::FakeGCMProfileService* gcm_service_;
diff --git a/chrome/browser/sharing/sharing_device_registration.cc b/chrome/browser/sharing/sharing_device_registration.cc index c0bfb13d..e546d11 100644 --- a/chrome/browser/sharing/sharing_device_registration.cc +++ b/chrome/browser/sharing/sharing_device_registration.cc
@@ -224,6 +224,6 @@ } void SharingDeviceRegistration::SetEnabledFeaturesForTesting( - std::set<SharingSpecificFields::EnabledFeatures> enabled_feautres) { - enabled_features_testing_value_ = std::move(enabled_feautres); + std::set<SharingSpecificFields::EnabledFeatures> enabled_features) { + enabled_features_testing_value_ = std::move(enabled_features); }
diff --git a/chrome/browser/sharing/sharing_device_registration.h b/chrome/browser/sharing/sharing_device_registration.h index 285b416..5e071e0 100644 --- a/chrome/browser/sharing/sharing_device_registration.h +++ b/chrome/browser/sharing/sharing_device_registration.h
@@ -54,7 +54,7 @@ // For testing void SetEnabledFeaturesForTesting( std::set<sync_pb::SharingSpecificFields_EnabledFeatures> - enabled_feautres); + enabled_features); private: FRIEND_TEST_ALL_PREFIXES(SharingDeviceRegistrationTest,
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc index 2b72ca3..008becb 100644 --- a/chrome/browser/sharing/sharing_service.cc +++ b/chrome/browser/sharing/sharing_service.cc
@@ -446,10 +446,10 @@ } void SharingService::RegisterDeviceInTesting( - std::set<sync_pb::SharingSpecificFields_EnabledFeatures> enabled_feautres, + std::set<sync_pb::SharingSpecificFields_EnabledFeatures> enabled_features, SharingDeviceRegistration::RegistrationCallback callback) { sharing_device_registration_->SetEnabledFeaturesForTesting( - std::move(enabled_feautres)); + std::move(enabled_features)); sharing_device_registration_->RegisterDevice(std::move(callback)); }
diff --git a/chrome/browser/sharing/sharing_service.h b/chrome/browser/sharing/sharing_service.h index 5bb5b0e..a7323035 100644 --- a/chrome/browser/sharing/sharing_service.h +++ b/chrome/browser/sharing/sharing_service.h
@@ -119,7 +119,7 @@ // Used to register devices with required capabilities in tests. void RegisterDeviceInTesting( - std::set<sync_pb::SharingSpecificFields_EnabledFeatures> enabled_feautres, + std::set<sync_pb::SharingSpecificFields_EnabledFeatures> enabled_features, SharingDeviceRegistration::RegistrationCallback callback); SharingSyncPreference* GetSyncPreferences() const;
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml index 20a668d..098a510 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
@@ -24,7 +24,10 @@ <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_margin="12dp" + android:layout_marginStart="12dp" + android:layout_marginEnd="12dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" android:layout_weight="1" android:orientation="vertical"> <TextView
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml index 0cff910..217ec91 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml
@@ -9,32 +9,24 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_marginBottom="16dp" - android:orientation="vertical" - android:paddingStart="16dp" - android:paddingEnd="16dp"> + android:orientation="vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:layout_marginEnd="@dimen/touch_to_fill_sheet_margin" - android:layout_marginStart="@dimen/touch_to_fill_sheet_margin" android:importantForAccessibility="no" app:srcCompat="@drawable/touch_to_fill_header_image" /> <org.chromium.ui.widget.TextViewWithLeading android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/touch_to_fill_sheet_margin" - android:layout_marginStart="@dimen/touch_to_fill_sheet_margin" android:layout_gravity="center_horizontal" android:text="@string/touch_to_fill_sheet_title" android:textAppearance="@style/TextAppearance.BlackHeadline" /> <org.chromium.ui.widget.TextViewWithLeading android:id="@+id/touch_to_fill_sheet_subtitle" - android:layout_marginEnd="@dimen/touch_to_fill_sheet_margin" - android:layout_marginStart="@dimen/touch_to_fill_sheet_margin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml index 67aba53..aa2743ce 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
@@ -9,7 +9,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_height="match_parent" android:layout_width="match_parent" - android:minHeight="340dp" android:orientation="vertical"> <ImageView @@ -29,11 +28,10 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:layout_marginTop="16dp" android:layout_marginEnd="@dimen/touch_to_fill_sheet_margin" android:layout_marginStart="@dimen/touch_to_fill_sheet_margin" android:clipToPadding="false" - android:paddingBottom="16dp" + android:paddingBottom="8dp" android:divider="@null" tools:listitem="@layout/touch_to_fill_credential_item"/>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml b/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml index 249a6ea..918ec23 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/values/dimens.xml
@@ -6,4 +6,6 @@ <resources> <dimen name="touch_to_fill_favicon_size">24dp</dimen> <dimen name="touch_to_fill_sheet_margin">16dp</dimen> + <dimen name="touch_to_fill_sheet_height_multiple_credentials">326dp</dimen> + <dimen name="touch_to_fill_sheet_height_single_credential">298dp</dimen> </resources>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java index 3752bed..f7b7c12 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.touch_to_fill; import android.content.Context; +import android.support.annotation.DimenRes; import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -128,7 +129,7 @@ @Override public int getPeekHeight() { - return Math.min(mContentView.getMinimumHeight(), + return Math.min(mContext.getResources().getDimensionPixelSize(getDesiredSheetHeight()), (int) mBottomSheetController.getBottomSheet().getSheetContainerHeight()); } @@ -161,4 +162,13 @@ public int getSheetClosedAccessibilityStringId() { return R.string.touch_to_fill_sheet_closed; } + + // TODO(crbug.com/1009331): This should add up the height of all items up to the 2nd credential. + private @DimenRes int getDesiredSheetHeight() { + if (mSheetItemListView.getAdapter() != null + && mSheetItemListView.getAdapter().getItemCount() > 2) { + return R.dimen.touch_to_fill_sheet_height_multiple_credentials; + } + return R.dimen.touch_to_fill_sheet_height_single_credential; + } }
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc index 3a48d76..27c6950a 100644 --- a/chrome/browser/ui/login/login_handler_browsertest.cc +++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -166,7 +166,14 @@ } } -class LoginPromptBrowserTest : public InProcessBrowserTest { +enum class SplitAuthCacheByNetworkIsolationKey { + kFalse, + kTrue, +}; + +class LoginPromptBrowserTest + : public InProcessBrowserTest, + public testing::WithParamInterface<SplitAuthCacheByNetworkIsolationKey> { public: LoginPromptBrowserTest() : bad_password_("incorrect"), @@ -178,8 +185,20 @@ auth_map_["bar"] = AuthInfo("testuser", "barpassword"); auth_map_["testrealm"] = AuthInfo(username_basic_, password_); - scoped_feature_list_.InitAndEnableFeature( - features::kHTTPAuthCommittedInterstitials); + if (GetParam() == SplitAuthCacheByNetworkIsolationKey::kFalse) { + scoped_feature_list_.InitWithFeatures( + // enabled_features + {features::kHTTPAuthCommittedInterstitials}, + // disabled_features + {features::kSplitAuthCacheByNetworkIsolationKey}); + } else { + scoped_feature_list_.InitWithFeatures( + // enabled_features + {features::kHTTPAuthCommittedInterstitials, + features::kSplitAuthCacheByNetworkIsolationKey}, + // disabled_features + {}); + } } void SetUpOnMainThread() override { @@ -213,6 +232,12 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +INSTANTIATE_TEST_SUITE_P( + /* no prefix */, + LoginPromptBrowserTest, + ::testing::Values(SplitAuthCacheByNetworkIsolationKey::kFalse, + SplitAuthCacheByNetworkIsolationKey::kTrue)); + void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) { const net::AuthChallengeInfo& challenge = handler->auth_info(); @@ -255,7 +280,7 @@ // correctness. Instead, it relies on the auth dialog blocking the // browser, and triggering a timeout to cause failure when the // prefetch resource requires authorization. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, PrefetchAuthCancels) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, PrefetchAuthCancels) { ASSERT_TRUE(embedded_test_server()->Start()); GURL test_page = embedded_test_server()->GetURL(kPrefetchAuthPage); @@ -295,7 +320,7 @@ } // Test that "Basic" HTTP authentication works. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestBasicAuth) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestBasicAuth) { ASSERT_TRUE(embedded_test_server()->Start()); GURL test_page = embedded_test_server()->GetURL(kAuthBasicPage); @@ -359,7 +384,7 @@ } // Test that "Digest" HTTP authentication works. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestDigestAuth) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestDigestAuth) { ASSERT_TRUE(embedded_test_server()->Start()); GURL test_page = embedded_test_server()->GetURL(kAuthDigestPage); @@ -409,7 +434,7 @@ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); } -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestTwoAuths) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestTwoAuths) { ASSERT_TRUE(embedded_test_server()->Start()); content::WebContents* contents1 = @@ -468,7 +493,7 @@ } // Test manual login prompt cancellation. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestCancelAuth_Manual) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestCancelAuth_Manual) { ASSERT_TRUE(embedded_test_server()->Start()); const GURL kAuthURL = embedded_test_server()->GetURL(kAuthBasicPage); @@ -495,7 +520,7 @@ } // Test login prompt cancellation on navigation to a new page. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestCancelAuth_OnNavigation) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestCancelAuth_OnNavigation) { ASSERT_TRUE(embedded_test_server()->Start()); const GURL kAuthURL = embedded_test_server()->GetURL(kAuthBasicPage); const GURL kNoAuthURL = embedded_test_server()->GetURL(kNoAuthPage1); @@ -521,7 +546,7 @@ } // Test login prompt cancellation on navigation to back. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestCancelAuth_OnBack) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestCancelAuth_OnBack) { ASSERT_TRUE(embedded_test_server()->Start()); const GURL kAuthURL = embedded_test_server()->GetURL(kAuthBasicPage); const GURL kNoAuthURL = embedded_test_server()->GetURL(kNoAuthPage1); @@ -552,7 +577,7 @@ } // Test login prompt cancellation on navigation to forward. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestCancelAuth_OnForward) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestCancelAuth_OnForward) { ASSERT_TRUE(embedded_test_server()->Start()); const GURL kAuthURL = embedded_test_server()->GetURL(kAuthBasicPage); const GURL kNoAuthURL1 = embedded_test_server()->GetURL(kNoAuthPage1); @@ -611,6 +636,12 @@ LoginPromptBrowserTestObserver login_prompt_observer_; }; +INSTANTIATE_TEST_SUITE_P( + /* no prefix */, + MultiRealmLoginPromptBrowserTest, + ::testing::Values(SplitAuthCacheByNetworkIsolationKey::kFalse, + SplitAuthCacheByNetworkIsolationKey::kTrue)); + template <class F> void MultiRealmLoginPromptBrowserTest::RunTest(const F& for_each_realm_func) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -652,7 +683,7 @@ } // Checks that cancelling works as expected. -IN_PROC_BROWSER_TEST_F(MultiRealmLoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(MultiRealmLoginPromptBrowserTest, MultipleRealmCancellation) { RunTest([this](LoginHandler* handler) { WindowedAuthCancelledObserver waiter(GetNavigationController()); @@ -666,7 +697,7 @@ } // Checks that supplying credentials works as expected. -IN_PROC_BROWSER_TEST_F(MultiRealmLoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(MultiRealmLoginPromptBrowserTest, MultipleRealmConfirmation) { RunTest([this](LoginHandler* handler) { WindowedAuthSuppliedObserver waiter(GetNavigationController()); @@ -681,7 +712,7 @@ // Testing for recovery from an incorrect password for the case where // there are multiple authenticated resources. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, IncorrectConfirmation) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, IncorrectConfirmation) { ASSERT_TRUE(embedded_test_server()->Start()); GURL test_page = embedded_test_server()->GetURL(kSingleRealmTestPage); @@ -748,7 +779,7 @@ // If the favicon is an authenticated resource, we shouldn't prompt // for credentials. The same URL, if requested elsewhere should // prompt for credentials. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, NoLoginPromptForFavicon) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, NoLoginPromptForFavicon) { const char kFaviconTestPage[] = "/login/has_favicon.html"; const char kFaviconResource[] = "/auth-basic/favicon.gif"; @@ -802,7 +833,7 @@ } // Block crossdomain image login prompting as a phishing defense. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, BlockCrossdomainPromptForSubresources) { const char kTestPage[] = "/login/load_img_from_b.html"; @@ -870,7 +901,7 @@ // Block same domain image resource if the top level frame is HTTPS and the // image resource is HTTP. // E.g. Top level: https://example.com, Image resource: http://example.com/image -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, BlockCrossdomainPromptForSubresourcesMixedContent) { ASSERT_TRUE(embedded_test_server()->Start()); net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); @@ -902,7 +933,7 @@ } // Allow crossdomain iframe login prompting despite the above. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, AllowCrossdomainPromptForSubframes) { const char kTestPage[] = "/login/load_iframe_from_b.html"; @@ -954,7 +985,7 @@ EXPECT_EQ(1, observer.auth_needed_count()); } -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, SupplyRedundantAuths) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, SupplyRedundantAuths) { ASSERT_TRUE(embedded_test_server()->Start()); // Get NavigationController for tab 1. @@ -1010,7 +1041,7 @@ EXPECT_EQ(0, observer.auth_cancelled_count()); } -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, CancelRedundantAuths) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, CancelRedundantAuths) { ASSERT_TRUE(embedded_test_server()->Start()); // Get NavigationController for tab 1. @@ -1066,7 +1097,7 @@ EXPECT_EQ(2, observer.auth_cancelled_count()); } -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, SupplyRedundantAuthsMultiProfile) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1134,7 +1165,7 @@ // If an XMLHttpRequest is made with incorrect credentials, there should be no // login prompt; instead the 401 status should be returned to the script. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, NoLoginPromptForXHRWithBadCredentials) { const char kXHRTestPage[] = "/login/xhr_with_credentials.html#incorrect"; @@ -1168,7 +1199,7 @@ // If an XMLHttpRequest is made with correct credentials, there should be no // login prompt either. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, NoLoginPromptForXHRWithGoodCredentials) { const char kXHRTestPage[] = "/login/xhr_with_credentials.html#secret"; @@ -1202,7 +1233,7 @@ // If an XMLHttpRequest is made without credentials, there should be a login // prompt. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, LoginPromptForXHRWithoutCredentials) { const char kXHRTestPage[] = "/login/xhr_without_credentials.html"; @@ -1265,7 +1296,7 @@ // If an XMLHttpRequest is made without credentials, there should be a login // prompt. If it's cancelled, the script should get a 401 status. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, LoginPromptForXHRWithoutCredentialsCancelled) { const char kXHRTestPage[] = "/login/xhr_without_credentials.html"; @@ -1307,9 +1338,88 @@ EXPECT_EQ(1, observer.auth_cancelled_count()); } +// Test that the auth cache respects NetworkIsolationKeys when splitting the +// cache based on the key is enabled. +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, + AuthCacheAcrossNetworkIsolationKeys) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL test_page = embedded_test_server()->GetURL(kAuthBasicPage); + + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + NavigationController* controller = &contents->GetController(); + + LoginPromptBrowserTestObserver observer; + observer.Register(content::Source<NavigationController>(controller)); + WindowedAuthNeededObserver auth_needed_waiter(controller); + browser()->OpenURL(OpenURLParams(test_page, Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + auth_needed_waiter.Wait(); + + ASSERT_EQ(1u, observer.handlers().size()); + WindowedAuthSuppliedObserver auth_supplied_waiter(controller); + LoginHandler* handler = *observer.handlers().begin(); + SetAuthFor(handler); + auth_supplied_waiter.Wait(); + + base::string16 expected_title = ExpectedTitleFromAuth( + base::ASCIIToUTF16("basicuser"), base::ASCIIToUTF16("secret")); + content::TitleWatcher title_watcher(contents, expected_title); + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); + EXPECT_EQ(1, observer.auth_needed_count()); + + base::RunLoop run_loop; + content::BrowserContext::GetDefaultStoragePartition(browser()->profile()) + ->GetNetworkContext() + ->ClearHttpCache(base::Time(), base::Time(), nullptr, + run_loop.QuitClosure()); + run_loop.Run(); + + // Navigate to a URL on a different origin that iframes the URL with the + // challenge. + GURL cross_origin_page = embedded_test_server()->GetURL( + "localhost", "/iframe?" + test_page.spec()); + if (GetParam() == SplitAuthCacheByNetworkIsolationKey::kFalse) { + // When allowing credentials to be used across NetworkIsolationKeys, the + // auth credentials should be reused and there should be no new auth dialog. + ui_test_utils::NavigateToURL(browser(), cross_origin_page); + EXPECT_EQ(0u, observer.handlers().size()); + EXPECT_EQ(1, observer.auth_needed_count()); + } else { + // When not allowing credentials to be used across NetworkIsolationKeys, + // there should be another auth challenge. + content::TestNavigationObserver navigation_observer(contents); + WindowedAuthNeededObserver auth_needed_waiter2(controller); + browser()->OpenURL(OpenURLParams(cross_origin_page, Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + auth_needed_waiter2.Wait(); + ASSERT_EQ(1u, observer.handlers().size()); + WindowedAuthSuppliedObserver auth_supplied_waiter(controller); + LoginHandler* handler = *observer.handlers().begin(); + SetAuthFor(handler); + auth_supplied_waiter.Wait(); + navigation_observer.Wait(); + EXPECT_EQ(2, observer.auth_needed_count()); + } + + std::vector<content::RenderFrameHost*> frames = contents->GetAllFrames(); + ASSERT_EQ(2u, frames.size()); + ASSERT_TRUE(frames[1]->IsDescendantOf(frames[0])); + ASSERT_EQ(test_page, frames[1]->GetLastCommittedURL()); + + // Make sure the iframe is displaying the base64-encoded credentials that + // should have been set, which the EmbeddedTestServer echos back in response + // bodies when /basic-auth is requested. + EXPECT_EQ(true, content::EvalJs(frames[1], + "document.documentElement.innerText.search(" + "'YmFzaWN1c2VyOnNlY3JldA==') >= 0")); +} + // If a cross origin direct navigation triggers a login prompt, the login // interstitial should be shown. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, ShowCorrectUrlForCrossOriginMainFrameRequests) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1321,7 +1431,7 @@ // Same as ShowCorrectUrlForCrossOriginMainFrameRequests, but happening in a // popup window. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, ShowCorrectUrlForCrossOriginMainFrameRequests_Popup) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1334,7 +1444,7 @@ // If a cross origin redirect triggers a login prompt, the destination URL // should be shown in the omnibox when the auth dialog is displayed. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, ShowCorrectUrlForCrossOriginMainFrameRedirects) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1359,7 +1469,7 @@ #define MAYBE_CancelLoginInterstitialOnRedirect \ CancelLoginInterstitialOnRedirect #endif -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, MAYBE_CancelLoginInterstitialOnRedirect) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1415,7 +1525,7 @@ // that ends up with an auth URL works fine. This can happen if a URL that // triggers the auth dialog can also trigger an SSL interstitial (or any other // type of interstitial). -IN_PROC_BROWSER_TEST_F( +IN_PROC_BROWSER_TEST_P( LoginPromptBrowserTest, DISABLED_LoginInterstitialShouldReplaceExistingInterstitial) { net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); @@ -1485,7 +1595,7 @@ // is any other interstitial being displayed. With committed SSL interstitials, // the navigation is actually cross domain since the interstitial is actually // a committed navigation, but we still expect the same behavior. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, ShouldReplaceExistingInterstitialWhenNavigated) { ASSERT_TRUE(embedded_test_server()->Start()); net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); @@ -1555,7 +1665,7 @@ // interstitial. If this test becomes flaky, it's likely that the logic that // prevents the tested scenario from happening got broken, rather than the test // itself. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, ShouldNotProceedExistingInterstitial) { net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); @@ -1600,13 +1710,13 @@ } // Test where Basic HTTP authentication is disabled. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, PRE_TestBasicAuthDisabled) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, PRE_TestBasicAuthDisabled) { // Disable all auth schemes. The modified list isn't respected until the // browser is restarted, however. g_browser_process->local_state()->SetString(prefs::kAuthSchemes, ""); } -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestBasicAuthDisabled) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, TestBasicAuthDisabled) { ASSERT_TRUE(embedded_test_server()->Start()); GURL test_page = embedded_test_server()->GetURL(kAuthBasicPage); @@ -1641,7 +1751,7 @@ // Tests that when HTTP Auth committed interstitials are enabled, a cross-origin // main-frame auth challenge cancels the auth request. -IN_PROC_BROWSER_TEST_F( +IN_PROC_BROWSER_TEST_P( LoginPromptBrowserTest, TestAuthChallengeCancelsNavigationWithCommittedInterstitials) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1664,7 +1774,7 @@ // Tests that when HTTP Auth committed interstitials are enabled, the login // prompt is shown on top of a committed error page when there is a cross-origin // main-frame auth challenge. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, PromptWithCommittedInterstitials) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1700,7 +1810,7 @@ // Tests that when HTTP Auth committed interstitials are enabled, showing a // login prompt in a new window opened from window.open() does not // crash. Regression test for https://crbug.com/1005096. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, PromptWithNoVisibleEntry) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, PromptWithNoVisibleEntry) { ASSERT_TRUE(embedded_test_server()->Start()); content::WebContents* contents = @@ -1744,7 +1854,7 @@ } // Tests that FTP auth challenges appear over a blank committed interstitial. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, FtpAuth) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, FtpAuth) { net::SpawnedTestServer ftp_server( net::SpawnedTestServer::TYPE_FTP, base::FilePath(FILE_PATH_LITERAL("chrome/test/data/ftp"))); @@ -1777,7 +1887,7 @@ // Tests that FTP auth prompts do not appear when credentials have been // previously entered and cached. -IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, FtpAuthWithCache) { +IN_PROC_BROWSER_TEST_P(LoginPromptBrowserTest, FtpAuthWithCache) { net::SpawnedTestServer ftp_server( net::SpawnedTestServer::TYPE_FTP, base::FilePath(FILE_PATH_LITERAL("chrome/test/data/ftp")));
diff --git a/chrome/browser/ui/login/login_tab_helper.cc b/chrome/browser/ui/login/login_tab_helper.cc index 2d18d03..2f78653 100644 --- a/chrome/browser/ui/login/login_tab_helper.cc +++ b/chrome/browser/ui/login/login_tab_helper.cc
@@ -121,6 +121,7 @@ } challenge_ = navigation_handle->GetAuthChallengeInfo().value(); + network_isolation_key_ = navigation_handle->GetNetworkIsolationKey(); url_for_delegate_ = navigation_handle->GetURL(); delegate_ = CreateLoginPrompt( @@ -202,7 +203,8 @@ content::BrowserContext::GetDefaultStoragePartition( web_contents()->GetBrowserContext()) ->GetNetworkContext() - ->AddAuthCacheEntry(challenge_, credentials.value(), + ->AddAuthCacheEntry(challenge_, network_isolation_key_, + credentials.value(), base::BindOnce(&LoginTabHelper::Reload, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/chrome/browser/ui/login/login_tab_helper.h b/chrome/browser/ui/login/login_tab_helper.h index a841aba..dd059ed 100644 --- a/chrome/browser/ui/login/login_tab_helper.h +++ b/chrome/browser/ui/login/login_tab_helper.h
@@ -9,6 +9,9 @@ #include "content/public/browser/navigation_throttle.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +#include "net/base/auth.h" +#include "net/base/network_isolation_key.h" +#include "url/gurl.h" namespace content { class LoginDelegate; @@ -71,6 +74,7 @@ GURL url_for_delegate_; net::AuthChallengeInfo challenge_; + net::NetworkIsolationKey network_isolation_key_; // Stores the navigation entry ID for a pending refresh due to a user // cancelling a login prompt. This is set to the visible navigation entry ID
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc index 9494912..57356aed 100644 --- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc +++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/passwords/password_generation_popup_controller_impl.h" +#include <memory> + #include "base/strings/utf_string_conversions.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/autofill/core/common/password_form.h" @@ -41,8 +43,9 @@ TEST_F(PasswordGenerationPopupControllerImplTest, GetOrCreateTheSame) { autofill::password_generation::PasswordGenerationUIData ui_data( - gfx::RectF(100, 20), 20 /*max_length*/, base::ASCIIToUTF16("element"), - 100 /*generation_element_id*/, base::i18n::TextDirection(), + gfx::RectF(100, 20), /*max_length=*/20, base::ASCIIToUTF16("element"), + /*generation_element_id=*/100, + /*is_generation_element_password_type=*/true, base::i18n::TextDirection(), autofill::PasswordForm()); ui_data.password_form.username_value = base::ASCIIToUTF16("Name"); ui_data.password_form.password_value = base::ASCIIToUTF16("12345"); @@ -64,8 +67,9 @@ TEST_F(PasswordGenerationPopupControllerImplTest, GetOrCreateDifferentBounds) { gfx::RectF rect(100, 20); autofill::password_generation::PasswordGenerationUIData ui_data( - rect, 20 /*max_length*/, base::ASCIIToUTF16("element"), - 100 /*generation_element_id*/, base::i18n::TextDirection(), + rect, /*max_length=*/20, base::ASCIIToUTF16("element"), + /*generation_element_id=*/100, + /*is_generation_element_password_type=*/true, base::i18n::TextDirection(), autofill::PasswordForm()); ui_data.password_form.username_value = base::ASCIIToUTF16("Name"); ui_data.password_form.password_value = base::ASCIIToUTF16("12345"); @@ -88,8 +92,9 @@ TEST_F(PasswordGenerationPopupControllerImplTest, GetOrCreateDifferentTabs) { autofill::password_generation::PasswordGenerationUIData ui_data( - gfx::RectF(100, 20), 20 /*max_length*/, base::ASCIIToUTF16("element"), - 100 /*generation_element_id*/, base::i18n::TextDirection(), + gfx::RectF(100, 20), /*max_length=*/20, base::ASCIIToUTF16("element"), + /*generation_element_id=*/100, + /*is_generation_element_password_type=*/true, base::i18n::TextDirection(), autofill::PasswordForm()); ui_data.password_form.username_value = base::ASCIIToUTF16("Name"); ui_data.password_form.password_value = base::ASCIIToUTF16("12345"); @@ -112,8 +117,9 @@ TEST_F(PasswordGenerationPopupControllerImplTest, GetOrCreateDifferentDrivers) { autofill::password_generation::PasswordGenerationUIData ui_data( - gfx::RectF(100, 20), 20 /*max_length*/, base::ASCIIToUTF16("element"), - 100 /*generation_element_id*/, base::i18n::TextDirection(), + gfx::RectF(100, 20), /*max_length=*/20, base::ASCIIToUTF16("element"), + /*generation_element_id=*/100, + /*is_generation_element_password_type=*/true, base::i18n::TextDirection(), autofill::PasswordForm()); ui_data.password_form.username_value = base::ASCIIToUTF16("Name"); ui_data.password_form.password_value = base::ASCIIToUTF16("12345"); @@ -137,8 +143,9 @@ TEST_F(PasswordGenerationPopupControllerImplTest, GetOrCreateDifferentElements) { autofill::password_generation::PasswordGenerationUIData ui_data( - gfx::RectF(100, 20), 20 /*max_length*/, base::ASCIIToUTF16("element"), - 100 /*generation_element_id*/, base::i18n::TextDirection(), + gfx::RectF(100, 20), /*max_length=*/20, base::ASCIIToUTF16("element"), + /*generation_element_id=*/100, + /*is_generation_element_password_type=*/true, base::i18n::TextDirection(), autofill::PasswordForm()); auto driver = CreateDriver(); std::unique_ptr<content::WebContents> web_contents = CreateTestWebContents(); @@ -159,8 +166,9 @@ TEST_F(PasswordGenerationPopupControllerImplTest, DestroyInPasswordAccepted) { autofill::password_generation::PasswordGenerationUIData ui_data( - gfx::RectF(100, 20), 20 /*max_length*/, base::ASCIIToUTF16("element"), - 100 /*generation_element_id*/, base::i18n::TextDirection(), + gfx::RectF(100, 20), /*max_length=*/20, base::ASCIIToUTF16("element"), + /*generation_element_id=*/100, + /*is_generation_element_password_type=*/true, base::i18n::TextDirection(), autofill::PasswordForm()); auto driver = CreateDriver(); std::unique_ptr<content::WebContents> web_contents = CreateTestWebContents();
diff --git a/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc b/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc index 83c6799..4ec380c 100644 --- a/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc +++ b/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc
@@ -26,11 +26,12 @@ : PasswordGenerationPopupControllerImpl( gfx::RectF(0, 0, 10, 10), autofill::password_generation::PasswordGenerationUIData( - gfx::RectF(0, 0, 10, 10), - 10, - base::string16(), - 100, - base::i18n::TextDirection(), + /*bounds=*/gfx::RectF(0, 0, 10, 10), + /*max_length=*/10, + /*generation_element=*/base::string16(), + /*generation_element_renderer_id=*/100, + /*is_generation_element_password_type=*/true, + /*text_direction=*/base::i18n::TextDirection(), PasswordForm()), password_manager::ContentPasswordManagerDriverFactory:: FromWebContents(web_contents)
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc new file mode 100644 index 0000000..d00f28c --- /dev/null +++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
@@ -0,0 +1,453 @@ +// Copyright 2019 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 "chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h" + +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/tabs/tab_strip.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/infobars/core/infobar.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/common/result_codes.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "ui/views/widget/widget.h" + +namespace { + +content::WebContents* GetWebContents(Browser* browser, int tab) { + return browser->tab_strip_model()->GetWebContentsAt(tab); +} + +InfoBarService* GetInfobarService(Browser* browser, int tab) { + return InfoBarService::FromWebContents(GetWebContents(browser, tab)); +} + +base::string16 GetInfobarMessageText(Browser* browser, int tab) { + return static_cast<ConfirmInfoBarDelegate*>( + GetInfobarService(browser, tab)->infobar_at(0)->delegate()) + ->GetMessageText(); +} + +content::DesktopMediaID GetDesktopMediaID(Browser* browser, int tab) { + content::RenderFrameHost* main_frame = + GetWebContents(browser, tab)->GetMainFrame(); + return content::DesktopMediaID( + content::DesktopMediaID::TYPE_WEB_CONTENTS, + content::DesktopMediaID::kNullId, + content::WebContentsMediaCaptureId(main_frame->GetProcess()->GetID(), + main_frame->GetRoutingID())); +} + +views::Widget* GetContentsBorder(Browser* browser) { + return BrowserView::GetBrowserViewForBrowser(browser) + ->contents_border_widget(); +} + +scoped_refptr<MediaStreamCaptureIndicator> GetCaptureIndicator() { + return MediaCaptureDevicesDispatcher::GetInstance() + ->GetMediaStreamCaptureIndicator(); +} + +void ActivateTab(Browser* browser, int tab) { + browser->tab_strip_model()->ActivateTabAt( + tab, {TabStripModel::GestureType::kMouse}); +} + +constexpr int kNoSharedTabIndex = -1; +} // namespace + +class TabSharingUIViewsBrowserTest : public InProcessBrowserTest { + public: + TabSharingUIViewsBrowserTest() {} + + void CreateUiAndStartSharing(Browser* browser, int tab) { + // Explicitly activate the shared tab in testing. + ActivateTab(browser, tab); + + tab_sharing_ui_ = + TabSharingUI::Create(GetDesktopMediaID(browser, tab), + base::UTF8ToUTF16("example-sharing.com")); + tab_sharing_ui_->OnStarted( + base::OnceClosure(), + base::BindRepeating(&TabSharingUIViewsBrowserTest::OnStartSharing, + base::Unretained(this))); + } + + // Verify that tab sharing infobars are displayed on all tabs, and content + // border and tab capture indicator are only visible on the shared tab. Pass + // |kNoSharedTabIndex| for |shared_tab_index| to indicate the shared tab is + // not in |browser|. + void VerifyUi(Browser* browser, + int shared_tab_index, + size_t infobar_count = 1, + bool has_border = true) { + views::Widget* contents_border = GetContentsBorder(browser); + EXPECT_EQ(has_border, contents_border != nullptr); + auto capture_indicator = GetCaptureIndicator(); + for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { + // All tabs have |infobar_count| tab sharing infobars. + InfoBarService* infobar_service = GetInfobarService(browser, i); + EXPECT_EQ(infobar_count, infobar_service->infobar_count()); + for (size_t j = 0; j < infobar_count; ++j) { + EXPECT_EQ(infobars::InfoBarDelegate::TAB_SHARING_INFOBAR_DELEGATE, + infobar_service->infobar_at(j)->delegate()->GetIdentifier()); + } + + // Content border is only visible on the shared tab. + if (has_border) { + ActivateTab(browser, i); + EXPECT_EQ(i == shared_tab_index, contents_border->IsVisible()); + } + + // Tab capture indicator is only displayed on the shared tab. + EXPECT_EQ(i == shared_tab_index, + capture_indicator->IsBeingMirrored(GetWebContents(browser, i))); + } + } + + void AddTabs(Browser* browser, int tab_count = 1) { + for (int i = 0; i < tab_count; ++i) { + AddTabAtIndexToBrowser(browser, 0, GURL(chrome::kChromeUINewTabURL), + ui::PAGE_TRANSITION_LINK, true); + } + } + + TabSharingUIViews* tab_sharing_ui_views() { + return static_cast<TabSharingUIViews*>(tab_sharing_ui_.get()); + } + + private: + void OnStartSharing(const content::DesktopMediaID& media_id) { + tab_sharing_ui_->OnStarted( + base::OnceClosure(), + base::BindRepeating(&TabSharingUIViewsBrowserTest::OnStartSharing, + base::Unretained(this))); + } + + std::unique_ptr<TabSharingUI> tab_sharing_ui_; +}; + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, StartSharing) { + AddTabs(browser(), 2); + + // Test that before sharing there are no infobars, content border or tab + // capture indicator. + VerifyUi(browser(), kNoSharedTabIndex, 0 /*infobar_count*/, + false /*has_border*/); + + // Create UI and start sharing the tab at index 1. + CreateUiAndStartSharing(browser(), 1); + + // Test that infobars were created, and contents border and tab capture + // indicator are displayed on the shared tab. + VerifyUi(browser(), 1); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, SwitchSharedTab) { + AddTabs(browser(), 2); + CreateUiAndStartSharing(browser(), 1); + + // Share a different tab. + ActivateTab(browser(), 2); + tab_sharing_ui_views()->StartSharing( + GetInfobarService(browser(), 2)->infobar_at(0)); + + // Test that the UI has been updated. + VerifyUi(browser(), 2); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, StopSharing) { + AddTabs(browser()); + CreateUiAndStartSharing(browser(), 1); + + tab_sharing_ui_views()->StopSharing(); + + // Test that the infobars have been removed, and the contents border and tab + // capture indicator are no longer visible. + VerifyUi(browser(), kNoSharedTabIndex, 0 /*infobar_count*/); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, CloseTab) { + AddTabs(browser(), 2); + CreateUiAndStartSharing(browser(), 1); + + // Close a tab different than the shared one and test that the UI has not + // changed. + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + tab_strip_model->CloseWebContentsAt(2, TabStripModel::CLOSE_NONE); + VerifyUi(browser(), 1); + + // Close the shared tab and verify that sharing is stopped, i.e. the UI is + // removed. + tab_strip_model->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE); + VerifyUi(browser(), kNoSharedTabIndex, 0 /*infobar_count*/); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, + CloseTabInIncognitoBrowser) { + AddTabs(browser(), 2); + + // Start sharing a tab in an incognito browser. + Browser* incognito_browser = CreateIncognitoBrowser(); + AddTabs(incognito_browser, 2); + CreateUiAndStartSharing(incognito_browser, 1); + VerifyUi(incognito_browser, 1); + VerifyUi(browser(), kNoSharedTabIndex, 1 /*infobar_count*/, + false /*has_border*/); + + // Close a tab different than the shared one and test that the UI has not + // changed. + TabStripModel* tab_strip_model = incognito_browser->tab_strip_model(); + tab_strip_model->CloseWebContentsAt(2, TabStripModel::CLOSE_NONE); + VerifyUi(incognito_browser, 1); + VerifyUi(browser(), kNoSharedTabIndex, 1, false); + + // Close the shared tab in the incognito browser and test that the UI is + // removed. + incognito_browser->tab_strip_model()->CloseWebContentsAt( + 1, TabStripModel::CLOSE_NONE); + VerifyUi(incognito_browser, kNoSharedTabIndex, 0 /*infobar_count*/); + VerifyUi(browser(), kNoSharedTabIndex, 0, false); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, KillTab) { + AddTabs(browser(), 2); + CreateUiAndStartSharing(browser(), 1); + + // Kill a tab different than the shared one. + content::WebContents* web_contents = GetWebContents(browser(), 0); + content::RenderProcessHost* process = + web_contents->GetMainFrame()->GetProcess(); + content::RenderProcessHostWatcher crash_observer( + process, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + process->Shutdown(content::RESULT_CODE_KILLED); + crash_observer.Wait(); + + // Verify that the sad tab does not have an infobar. + InfoBarService* infobar_service = GetInfobarService(browser(), 0); + EXPECT_EQ(0u, infobar_service->infobar_count()); + + // Stop sharing should not result in a crash. + tab_sharing_ui_views()->StopSharing(); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, KillSharedTab) { + AddTabs(browser(), 2); + CreateUiAndStartSharing(browser(), 1); + + // Kill the shared tab. + content::WebContents* shared_tab_web_contents = GetWebContents(browser(), 1); + content::RenderProcessHost* shared_tab_process = + shared_tab_web_contents->GetMainFrame()->GetProcess(); + content::RenderProcessHostWatcher shared_tab_crash_observer( + shared_tab_process, + content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + shared_tab_process->Shutdown(content::RESULT_CODE_KILLED); + shared_tab_crash_observer.Wait(); + + // Verify that killing the shared tab stopped sharing. + VerifyUi(browser(), kNoSharedTabIndex, 0); +} + +IN_PROC_BROWSER_TEST_F(TabSharingUIViewsBrowserTest, + InfobarLabelUpdatedOnNavigation) { + AddTabs(browser()); + CreateUiAndStartSharing(browser(), 0); + ASSERT_THAT(base::UTF16ToUTF8(GetInfobarMessageText(browser(), 1)), + ::testing::HasSubstr(chrome::kChromeUINewTabHost)); + + ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL)); + EXPECT_THAT(base::UTF16ToUTF8(GetInfobarMessageText(browser(), 1)), + ::testing::HasSubstr(chrome::kChromeUIVersionHost)); + + ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); + EXPECT_THAT(base::UTF16ToUTF8(GetInfobarMessageText(browser(), 1)), + ::testing::HasSubstr("about:blank")); +} + +namespace { + +class DragObserver : public content::NotificationObserver { + public: + DragObserver() { + registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, + content::NotificationService::AllSources()); + } + + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override { + run_loop_.QuitWhenIdle(); + } + void Wait() & { run_loop_.Run(); } + + private: + content::NotificationRegistrar registrar_; + base::RunLoop run_loop_; +}; +} // namespace + +class TabDragTabSharingUIViewsBrowserTest + : public TabSharingUIViewsBrowserTest { + public: + TabDragTabSharingUIViewsBrowserTest() {} + + void DragTab(Browser* browser, int tab) { + TabStrip* tab_strip = + BrowserView::GetBrowserViewForBrowser(browser)->tabstrip(); + DragObserver observer; + size_t browser_count = BrowserList::GetInstance()->size(); + const gfx::Point tab_center = + ui_test_utils::GetCenterInScreenCoordinates(tab_strip->tab_at(tab)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_center) && + ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, + ui_controls::DOWN)); + // Drag the tab enough so that it detaches. + const gfx::Point drag_location = + tab_center + gfx::Vector2d(0, tab_strip->height() * 2); + ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone( + drag_location.x(), drag_location.y(), + base::BindOnce( + &TabDragTabSharingUIViewsBrowserTest::ReleaseInputAfterDrag, + base::Unretained(this), browser_count + 1))); + observer.Wait(); + } + + void ReleaseInputAfterDrag(size_t browser_count) { + if (BrowserList::GetInstance()->size() != browser_count) { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce( + &TabDragTabSharingUIViewsBrowserTest::ReleaseInputAfterDrag, + base::Unretained(this), browser_count), + base::TimeDelta::FromMilliseconds(1)); + return; + } + + ASSERT_TRUE( + ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP)); + } +}; + +IN_PROC_BROWSER_TEST_F(TabDragTabSharingUIViewsBrowserTest, DragTab) { + AddTabs(browser()); + CreateUiAndStartSharing(browser(), 1); + + DragTab(browser(), 0); + + BrowserList* browser_list = BrowserList::GetInstance(); + ASSERT_EQ(browser_list->size(), 2u); + ASSERT_EQ(browser_list->get(0), browser()); + VerifyUi(browser(), 0); + VerifyUi(browser_list->get(1), kNoSharedTabIndex, 1 /*infobar_count*/, + false /*has_border*/); +} + +IN_PROC_BROWSER_TEST_F(TabDragTabSharingUIViewsBrowserTest, DragSharedTab) { + AddTabs(browser()); + CreateUiAndStartSharing(browser(), 1); + + DragTab(browser(), 1); + + BrowserList* browser_list = BrowserList::GetInstance(); + ASSERT_EQ(browser_list->size(), 2u); + ASSERT_EQ(browser_list->get(0), browser()); + VerifyUi(browser(), kNoSharedTabIndex); + VerifyUi(browser_list->get(1), 0); +} + +class MultipleTabSharingUIViewsBrowserTest : public InProcessBrowserTest { + public: + MultipleTabSharingUIViewsBrowserTest() {} + + void CreateUIsAndStartSharing(Browser* browser, + int tab_index, + int tab_count) { + for (int i = 0; i < tab_count; ++i) { + int tab = tab_index + i; + ActivateTab(browser, tab); + tab_sharing_ui_views_.push_back( + TabSharingUI::Create(GetDesktopMediaID(browser, tab), + base::UTF8ToUTF16("example-sharing.com"))); + tab_sharing_ui_views_[tab_sharing_ui_views_.size() - 1]->OnStarted( + base::OnceClosure(), content::MediaStreamUI::SourceCallback()); + } + } + + TabSharingUIViews* tab_sharing_ui_views(int i) { + return static_cast<TabSharingUIViews*>(tab_sharing_ui_views_[i].get()); + } + + void AddTabs(Browser* browser, int tab_count) { + for (int i = 0; i < tab_count; ++i) + AddBlankTabAndShow(browser); + } + + private: + std::vector<std::unique_ptr<TabSharingUI>> tab_sharing_ui_views_; +}; + +IN_PROC_BROWSER_TEST_F(MultipleTabSharingUIViewsBrowserTest, VerifyUi) { + AddTabs(browser(), 3); + CreateUIsAndStartSharing(browser(), 1, 3); + + // Check that all tabs have 3 infobars corresponding to the 3 sharing + // sessions. + int tab_count = browser()->tab_strip_model()->count(); + for (int i = 0; i < tab_count; ++i) + EXPECT_EQ(3u, GetInfobarService(browser(), i)->infobar_count()); + + // Check that all shared tabs display a tab capture indicator. + auto capture_indicator = GetCaptureIndicator(); + for (int i = 1; i < tab_count; ++i) + EXPECT_TRUE( + capture_indicator->IsBeingMirrored(GetWebContents(browser(), i))); + + // Check that the border is only displayed on the last shared tab (known + // limitation https://crbug.com/996631). + views::Widget* contents_border = GetContentsBorder(browser()); + for (int i = 0; i < tab_count; ++i) { + ActivateTab(browser(), i); + EXPECT_EQ(i == 3, contents_border->IsVisible()); + } +} + +IN_PROC_BROWSER_TEST_F(MultipleTabSharingUIViewsBrowserTest, StopSharing) { + AddTabs(browser(), 3); + CreateUIsAndStartSharing(browser(), 1, 3); + + // Stop sharing tabs one by one and check that infobars are removed as well. + size_t shared_tab_count = 3; + while (shared_tab_count) { + tab_sharing_ui_views(--shared_tab_count)->StopSharing(); + for (int j = 0; j < browser()->tab_strip_model()->count(); ++j) + EXPECT_EQ(shared_tab_count, + GetInfobarService(browser(), j)->infobar_count()); + } +} + +IN_PROC_BROWSER_TEST_F(MultipleTabSharingUIViewsBrowserTest, CloseTabs) { + AddTabs(browser(), 3); + CreateUIsAndStartSharing(browser(), 1, 3); + + // Close shared tabs one by one and check that infobars are removed as well. + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + while (tab_strip_model->count() > 1) { + tab_strip_model->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE); + for (int i = 0; i < tab_strip_model->count(); ++i) + EXPECT_EQ(tab_strip_model->count() - 1u, + GetInfobarService(browser(), i)->infobar_count()); + } +}
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index f7de5a6f..0654a84 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -18,6 +18,7 @@ #include "base/command_line.h" #include "base/location.h" #include "base/memory/ptr_util.h" +#include "base/optional.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" @@ -27,7 +28,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/extensions/browsertest_util.h" #include "chrome/browser/installable/installable_metrics.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -42,6 +42,7 @@ #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/browser/ui/views/tabs/window_finder.h" #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h" +#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/browser/web_applications/components/web_app_install_utils.h" @@ -627,29 +628,25 @@ Browser* GetTerminalAppBrowser() { // Install the app (but only once per session). - if (!terminal_app_extension_) { + if (!terminal_app_id_) { GURL app_url = embedded_test_server()->GetURL("app.com", "/simple.html"); auto web_app_info = std::make_unique<WebApplicationInfo>(); web_app_info->app_url = app_url; web_app_info->scope = app_url.GetWithoutFilename(); web_app_info->open_as_window = true; - web_app::AppId app_id = InstallWebApp(std::move(web_app_info)); + terminal_app_id_ = InstallWebApp(std::move(web_app_info)); auto* provider = web_app::WebAppProvider::Get(browser()->profile()); provider->system_web_app_manager().SetSystemAppsForTesting( {{web_app::SystemAppType::TERMINAL, web_app::SystemAppInfo(app_url)}}); web_app::ExternallyInstalledWebAppPrefs(browser()->profile()->GetPrefs()) - .Insert(app_url, app_id, + .Insert(app_url, *terminal_app_id_, web_app::ExternalInstallSource::kInternalDefault); - - terminal_app_extension_ = - extensions::ExtensionRegistry::Get(browser()->profile()) - ->GetInstalledExtension(app_id); } - return extensions::browsertest_util::LaunchAppBrowser( - browser()->profile(), terminal_app_extension_); + return web_app::LaunchWebAppBrowser(browser()->profile(), + *terminal_app_id_); } Browser* browser() const { return InProcessBrowserTest::browser(); } @@ -659,7 +656,7 @@ // The root window for the event generator. aura::Window* root_ = nullptr; #endif - const extensions::Extension* terminal_app_extension_ = nullptr; + base::Optional<web_app::AppId> terminal_app_id_; DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest); };
diff --git a/chrome/browser/ui/webui/chromeos/login/l10n_util.cc b/chrome/browser/ui/webui/chromeos/login/l10n_util.cc index 8ec89e8..7392dc3 100644 --- a/chrome/browser/ui/webui/chromeos/login/l10n_util.cc +++ b/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
@@ -354,8 +354,12 @@ std::string selected_language; if (!language_switch_result) { - selected_language = - StartupCustomizationDocument::GetInstance()->initial_locale_default(); + if (!g_browser_process->GetApplicationLocale().empty()) { + selected_language = g_browser_process->GetApplicationLocale(); + } else { + selected_language = + StartupCustomizationDocument::GetInstance()->initial_locale_default(); + } } else { if (language_switch_result->success) { if (language_switch_result->requested_locale ==
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc index 0cacb0b..d7a5a6f 100644 --- a/chrome/browser/ui/webui/site_settings_helper.cc +++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -121,6 +121,7 @@ {CONTENT_SETTINGS_TYPE_WAKE_LOCK_SCREEN, nullptr}, {CONTENT_SETTINGS_TYPE_WAKE_LOCK_SYSTEM, nullptr}, {CONTENT_SETTINGS_TYPE_LEGACY_COOKIE_ACCESS, nullptr}, + {CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, nullptr}, }; static_assert(base::size(kContentSettingsTypeGroupNames) == // ContentSettingsType starts at -1, so add 1 here.
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn index 821b78f7..f91bf3ca 100644 --- a/chrome/browser/web_applications/components/BUILD.gn +++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -90,10 +90,12 @@ } deps = [ + "//base/util/values:values_util", "//chrome/app/resources:platform_locale_settings", "//chrome/app/theme:chrome_unscaled_resources", "//chrome/browser/web_applications:web_app_group", "//chrome/common", + "//components/content_settings/core/browser", "//components/crx_file", "//components/favicon/content", "//components/keyed_service/content",
diff --git a/chrome/browser/web_applications/components/manifest_update_manager.cc b/chrome/browser/web_applications/components/manifest_update_manager.cc index 63936805..48fb08c 100644 --- a/chrome/browser/web_applications/components/manifest_update_manager.cc +++ b/chrome/browser/web_applications/components/manifest_update_manager.cc
@@ -5,12 +5,69 @@ #include "chrome/browser/web_applications/components/manifest_update_manager.h" #include "base/metrics/histogram_macros.h" +#include "base/util/values/values_util.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/components/app_registrar.h" #include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/common/chrome_features.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/content_settings_types.h" namespace web_app { -ManifestUpdateManager::ManifestUpdateManager() = default; +namespace { + +const char kLastUpdateCheckKey[] = "last_update_check"; + +class AppPrefs { + public: + AppPrefs(Profile* profile, const GURL& origin) { + settings_ = HostContentSettingsMapFactory::GetForProfile(profile); + if (!settings_) + return; + origin_data_ = settings_->GetWebsiteSetting( + origin, GURL(), CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, + std::string(), nullptr); + } + + bool IsAvailable() const { return settings_; } + + const base::Value* GetAppData(const AppId& app_id) const { + if (!origin_data_) + return nullptr; + return origin_data_->FindKey(app_id); + } + + base::Value& GetAppDataMutable(const AppId& app_id) { + DCHECK(IsAvailable()); + if (!origin_data_) + origin_data_ = + std::make_unique<base::Value>(base::Value::Type::DICTIONARY); + base::Value* app_data = origin_data_->FindKey(app_id); + if (!app_data) { + app_data = origin_data_->SetKey( + app_id, base::Value(base::Value::Type::DICTIONARY)); + } + return *app_data; + } + + void Save(const GURL& origin) { + DCHECK(IsAvailable()); + settings_->SetWebsiteSettingDefaultScope( + origin, GURL(), CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, + std::string(), std::move(origin_data_)); + } + + private: + HostContentSettingsMap* settings_ = nullptr; + std::unique_ptr<base::Value> origin_data_; +}; + +} // namespace + +ManifestUpdateManager::ManifestUpdateManager(Profile* profile) + : profile_(profile) {} ManifestUpdateManager::~ManifestUpdateManager() = default; @@ -49,7 +106,7 @@ if (base::Contains(tasks_, app_id)) return; - if (!MaybeConsumeUpdateCheck(app_id)) { + if (!MaybeConsumeUpdateCheck(url.GetOrigin(), app_id)) { NotifyResult(url, ManifestUpdateResult::kThrottled); return; } @@ -73,20 +130,48 @@ DCHECK(!tasks_.contains(app_id)); } -bool ManifestUpdateManager::MaybeConsumeUpdateCheck(const AppId& app_id) { - base::Time now = time_override_for_testing_.value_or(base::Time::Now()); - base::Time& last_check_time = last_check_times_[app_id]; +bool ManifestUpdateManager::MaybeConsumeUpdateCheck(const GURL& origin, + const AppId& app_id) { + base::Optional<base::Time> last_check_time = + GetLastUpdateCheckTime(origin, app_id); + if (!last_check_time) + return false; + base::Time now = time_override_for_testing_.value_or(base::Time::Now()); // Throttling updates to at most once per day is consistent with Android. // See |UPDATE_INTERVAL| in WebappDataStorage.java. constexpr base::TimeDelta kDelayBetweenChecks = base::TimeDelta::FromDays(1); - if (now < last_check_time + kDelayBetweenChecks) + if (now < *last_check_time + kDelayBetweenChecks) return false; - last_check_time = now; + SetLastUpdateCheckTime(origin, app_id, now); return true; } +base::Optional<base::Time> ManifestUpdateManager::GetLastUpdateCheckTime( + const GURL& origin, + const AppId& app_id) const { + AppPrefs app_prefs(profile_, origin); + if (!app_prefs.IsAvailable()) + return base::nullopt; + const base::Value* app_data = app_prefs.GetAppData(app_id); + if (!app_data) + return base::Time(); + return util::ValueToTime(app_data->FindKey(kLastUpdateCheckKey)) + .value_or(base::Time()); +} + +void ManifestUpdateManager::SetLastUpdateCheckTime(const GURL& origin, + const AppId& app_id, + base::Time time) { + AppPrefs app_prefs(profile_, origin); + if (!app_prefs.IsAvailable()) + return; + base::Value& app_data = app_prefs.GetAppDataMutable(app_id); + app_data.SetKey(kLastUpdateCheckKey, util::TimeToValue(time)); + app_prefs.Save(origin); +} + void ManifestUpdateManager::OnUpdateStopped(const ManifestUpdateTask& task, ManifestUpdateResult result) { DCHECK_EQ(&task, tasks_[task.app_id()].get());
diff --git a/chrome/browser/web_applications/components/manifest_update_manager.h b/chrome/browser/web_applications/components/manifest_update_manager.h index de7c0de..c6430a6 100644 --- a/chrome/browser/web_applications/components/manifest_update_manager.h +++ b/chrome/browser/web_applications/components/manifest_update_manager.h
@@ -17,6 +17,8 @@ #include "chrome/browser/web_applications/components/manifest_update_task.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" +class Profile; + namespace content { class WebContents; } @@ -32,7 +34,7 @@ // of being triggered by page loads. class ManifestUpdateManager final : public AppRegistrarObserver { public: - ManifestUpdateManager(); + explicit ManifestUpdateManager(Profile* profile); ~ManifestUpdateManager() override; void SetSubsystems(AppRegistrar* registrar, @@ -61,11 +63,17 @@ } private: - bool MaybeConsumeUpdateCheck(const AppId& app_id); + bool MaybeConsumeUpdateCheck(const GURL& origin, const AppId& app_id); + base::Optional<base::Time> GetLastUpdateCheckTime(const GURL& origin, + const AppId& app_id) const; + void SetLastUpdateCheckTime(const GURL& origin, + const AppId& app_id, + base::Time time); void OnUpdateStopped(const ManifestUpdateTask& task, ManifestUpdateResult result); void NotifyResult(const GURL& url, ManifestUpdateResult result); + Profile* const profile_ = nullptr; AppRegistrar* registrar_ = nullptr; WebAppUiManager* ui_manager_ = nullptr; InstallManager* install_manager_ = nullptr; @@ -74,9 +82,6 @@ base::flat_map<AppId, std::unique_ptr<ManifestUpdateTask>> tasks_; - // TODO(crbug.com/926083): Store this in prefs instead of RAM. - base::flat_map<AppId, base::Time> last_check_times_; - base::Optional<base::Time> time_override_for_testing_; ResultCallback result_callback_for_testing_;
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index c1dbccf8..65d4719a 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -159,7 +159,7 @@ audio_focus_id_map_ = std::make_unique<WebAppAudioFocusIdMap>(); ui_manager_ = WebAppUiManager::Create(profile); install_manager_ = std::make_unique<WebAppInstallManager>(profile); - manifest_update_manager_ = std::make_unique<ManifestUpdateManager>(); + manifest_update_manager_ = std::make_unique<ManifestUpdateManager>(profile); pending_app_manager_ = std::make_unique<PendingAppManagerImpl>(profile); external_web_app_manager_ = std::make_unique<ExternalWebAppManager>(profile); system_web_app_manager_ = std::make_unique<SystemWebAppManager>(profile);
diff --git a/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc b/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc index 04df59b..0ea9cc1 100644 --- a/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc +++ b/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc
@@ -254,10 +254,10 @@ CHECK_EQ(RESULT_CODE_SUCCESS, StartSandboxTarget(MakeCmdLine("EngineSandboxMain"), &engine_setup_hooks, SandboxType::kTest)); - json_parser_ptr_ = std::make_unique<chrome_cleaner::UniqueParserPtr>( - parser_setup_hooks.TakeParserPtr()); + json_parser_ = std::make_unique<chrome_cleaner::RemoteParserPtr>( + parser_setup_hooks.TakeParserRemote()); return std::make_unique<chrome_cleaner::SandboxedJsonParser>( - mojo_task_runner_.get(), json_parser_ptr_.get()->get()); + mojo_task_runner_.get(), json_parser_.get()->get()); } protected: @@ -272,7 +272,7 @@ testing::NiceMock<MockLoggingService> mock_logging_service_; base::FilePath fake_apps_dir_; base::FilePath chrome_dir_; - std::unique_ptr<chrome_cleaner::UniqueParserPtr> json_parser_ptr_; + std::unique_ptr<chrome_cleaner::RemoteParserPtr> json_parser_; scoped_refptr<chrome_cleaner::EngineClient> engine_client_; chrome_cleaner::TestPUPData test_pup_data_; std::unique_ptr<ScopedFile> uws_A_;
diff --git a/chrome/chrome_cleaner/executables/chrome_cleaner_main.cc b/chrome/chrome_cleaner/executables/chrome_cleaner_main.cc index 0cedc2a..fc616d08 100644 --- a/chrome/chrome_cleaner/executables/chrome_cleaner_main.cc +++ b/chrome/chrome_cleaner/executables/chrome_cleaner_main.cc
@@ -212,21 +212,20 @@ chrome_cleaner::SandboxConnectionErrorCallback connection_error_callback = main_controller.GetSandboxConnectionErrorCallback(); - // Initialize a null UniqueParserPtr to be set by SpawnParserSandbox. - chrome_cleaner::UniqueParserPtr parser_ptr( - nullptr, base::OnTaskRunnerDeleter(nullptr)); + // Initialize a null RemoteParserPtr to be set by SpawnParserSandbox. + chrome_cleaner::RemoteParserPtr parser(nullptr, + base::OnTaskRunnerDeleter(nullptr)); chrome_cleaner::ResultCode init_result = chrome_cleaner::SpawnParserSandbox( - shutdown_sequence.mojo_task_runner, connection_error_callback, - &parser_ptr); + shutdown_sequence.mojo_task_runner, connection_error_callback, &parser); if (init_result != chrome_cleaner::RESULT_CODE_SUCCESS) { return init_result; } std::unique_ptr<chrome_cleaner::SandboxedJsonParser> json_parser = std::make_unique<chrome_cleaner::SandboxedJsonParser>( - shutdown_sequence.mojo_task_runner.get(), parser_ptr.get()); + shutdown_sequence.mojo_task_runner.get(), parser.get()); std::unique_ptr<chrome_cleaner::SandboxedShortcutParser> shortcut_parser = std::make_unique<chrome_cleaner::SandboxedShortcutParser>( - shutdown_sequence.mojo_task_runner.get(), parser_ptr.get()); + shutdown_sequence.mojo_task_runner.get(), parser.get()); chrome_cleaner::Settings* settings = chrome_cleaner::Settings::GetInstance(); if (!chrome_cleaner::IsSupportedEngine(settings->engine())) {
diff --git a/chrome/chrome_cleaner/executables/chrome_reporter_main.cc b/chrome/chrome_cleaner/executables/chrome_reporter_main.cc index b86d1c0..eabbcaf7 100644 --- a/chrome/chrome_cleaner/executables/chrome_reporter_main.cc +++ b/chrome/chrome_cleaner/executables/chrome_reporter_main.cc
@@ -286,17 +286,17 @@ DCHECK(succeeded) << "TaskScheduler::Initialize() failed"; // Initialize the sandbox for the shortcut parser. - chrome_cleaner::UniqueParserPtr parser_ptr( - nullptr, base::OnTaskRunnerDeleter(nullptr)); + chrome_cleaner::RemoteParserPtr parser(nullptr, + base::OnTaskRunnerDeleter(nullptr)); chrome_cleaner::ResultCode parser_result_code = chrome_cleaner::SpawnParserSandbox( shutdown_sequence.mojo_task_runner.get(), - sandbox_connection_error_callback, &parser_ptr); + sandbox_connection_error_callback, &parser); if (parser_result_code != chrome_cleaner::RESULT_CODE_SUCCESS) return FinalizeWithResultCode(parser_result_code, ®istry_logger); std::unique_ptr<chrome_cleaner::ShortcutParserAPI> shortcut_parser = std::make_unique<chrome_cleaner::SandboxedShortcutParser>( - shutdown_sequence.mojo_task_runner.get(), parser_ptr.get()); + shutdown_sequence.mojo_task_runner.get(), parser.get()); std::unique_ptr<chrome_cleaner::ScannerController> scanner_controller = std::make_unique<chrome_cleaner::ScannerControllerImpl>(
diff --git a/chrome/chrome_cleaner/parsers/broker/json_parser_sandbox_setup_unittest.cc b/chrome/chrome_cleaner/parsers/broker/json_parser_sandbox_setup_unittest.cc index e9b6ff5..94cf2bc 100644 --- a/chrome/chrome_cleaner/parsers/broker/json_parser_sandbox_setup_unittest.cc +++ b/chrome/chrome_cleaner/parsers/broker/json_parser_sandbox_setup_unittest.cc
@@ -8,11 +8,11 @@ #include "base/test/multiprocess_test.h" #include "base/test/test_timeouts.h" #include "base/time/time.h" -#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" +#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.h" #include "chrome/chrome_cleaner/parsers/target/sandbox_setup.h" -#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/remote.h" #include "sandbox/win/src/sandbox_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" @@ -31,7 +31,7 @@ class JsonParserSandboxSetupTest : public base::MultiProcessTest { public: JsonParserSandboxSetupTest() - : parser_ptr_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {} + : parser_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {} void SetUp() override { mojo_task_runner_ = MojoTaskRunner::Create(); @@ -41,12 +41,12 @@ ASSERT_EQ(RESULT_CODE_SUCCESS, StartSandboxTarget(MakeCmdLine("JsonParserSandboxTargetMain"), &setup_hooks, SandboxType::kTest)); - parser_ptr_ = setup_hooks.TakeParserPtr(); + parser_ = setup_hooks.TakeParserRemote(); } protected: scoped_refptr<MojoTaskRunner> mojo_task_runner_; - UniqueParserPtr parser_ptr_; + RemoteParserPtr parser_; }; void ParseCallbackExpectedKeyValue(const std::string& expected_key, @@ -93,15 +93,14 @@ WaitableEvent::InitialState::NOT_SIGNALED); mojo_task_runner_->PostTask( - FROM_HERE, base::BindOnce( - [](mojom::ParserPtr* parser_ptr, WaitableEvent* done) { - (*parser_ptr) - ->ParseJson( - kTestText, - base::BindOnce(&ParseCallbackExpectedKeyValue, - kTestKey, kTestValue, done)); - }, - parser_ptr_.get(), &done)); + FROM_HERE, + base::BindOnce( + [](mojo::Remote<mojom::Parser>* parser, WaitableEvent* done) { + (*parser)->ParseJson(kTestText, + base::BindOnce(&ParseCallbackExpectedKeyValue, + kTestKey, kTestValue, done)); + }, + parser_.get(), &done)); EXPECT_TRUE(done.TimedWait(TestTimeouts::action_timeout())); } @@ -112,12 +111,12 @@ mojo_task_runner_->PostTask( FROM_HERE, base::BindOnce( - [](mojom::ParserPtr* parser_ptr, WaitableEvent* done) { - (*parser_ptr) - ->ParseJson(kInvalidText, - base::BindOnce(&ParseCallbackExpectedError, done)); + [](mojo::Remote<mojom::Parser>* parser, WaitableEvent* done) { + (*parser)->ParseJson( + kInvalidText, + base::BindOnce(&ParseCallbackExpectedError, done)); }, - parser_ptr_.get(), &done)); + parser_.get(), &done)); EXPECT_TRUE(done.TimedWait(TestTimeouts::action_timeout())); }
diff --git a/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc b/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc index 1ddbb727..6d89d3e4 100644 --- a/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc +++ b/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc
@@ -28,7 +28,7 @@ class LnkParserSandboxSetupTest : public base::MultiProcessTest { public: LnkParserSandboxSetupTest() - : parser_ptr_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {} + : parser_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {} void SetUp() override { mojo_task_runner_ = MojoTaskRunner::Create(); @@ -38,9 +38,9 @@ ASSERT_EQ(RESULT_CODE_SUCCESS, StartSandboxTarget(MakeCmdLine("LnkParserSandboxTargetMain"), &setup_hooks, SandboxType::kTest)); - parser_ptr_ = setup_hooks.TakeParserPtr(); + parser_ = setup_hooks.TakeParserRemote(); shortcut_parser_ = std::make_unique<SandboxedShortcutParser>( - mojo_task_runner_.get(), parser_ptr_.get()); + mojo_task_runner_.get(), parser_.get()); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), @@ -49,7 +49,7 @@ protected: scoped_refptr<MojoTaskRunner> mojo_task_runner_; - UniqueParserPtr parser_ptr_; + RemoteParserPtr parser_; std::unique_ptr<ShortcutParserAPI> shortcut_parser_; ParsedLnkFile test_parsed_shortcut_;
diff --git a/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.cc b/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.cc index a0763a1d..2cd03ef 100644 --- a/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.cc +++ b/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.cc
@@ -8,7 +8,10 @@ #include "base/bind.h" #include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h" +#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/settings/settings_types.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" namespace chrome_cleaner { @@ -17,47 +20,46 @@ base::OnceClosure connection_error_handler) : mojo_task_runner_(mojo_task_runner), connection_error_handler_(std::move(connection_error_handler)), - parser_ptr_(new mojom::ParserPtr(), - base::OnTaskRunnerDeleter(mojo_task_runner_)) {} + parser_(new mojo::Remote<mojom::Parser>(), + base::OnTaskRunnerDeleter(mojo_task_runner_)) {} ParserSandboxSetupHooks::~ParserSandboxSetupHooks() = default; ResultCode ParserSandboxSetupHooks::UpdateSandboxPolicy( sandbox::TargetPolicy* policy, base::CommandLine* command_line) { - // Unretained reference is safe because the parser_ptr is taken by the + // Unretained reference is safe because the parser remote is taken by the // caller and is expected to retain it for the life of the sandboxed process. mojo_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&ParserSandboxSetupHooks::BindParserPtr, + FROM_HERE, base::BindOnce(&ParserSandboxSetupHooks::BindParserRemote, base::Unretained(this), SetupSandboxMessagePipe(policy, command_line), - base::Unretained(parser_ptr_.get()))); + base::Unretained(parser_.get()))); return RESULT_CODE_SUCCESS; } -void ParserSandboxSetupHooks::BindParserPtr( +void ParserSandboxSetupHooks::BindParserRemote( mojo::ScopedMessagePipeHandle pipe_handle, - mojom::ParserPtr* parser_ptr) { - parser_ptr->Bind(mojom::ParserPtrInfo(std::move(pipe_handle), 0)); - parser_ptr->set_connection_error_handler( - std::move(connection_error_handler_)); + mojo::Remote<mojom::Parser>* parser) { + parser->Bind(mojo::PendingRemote<mojom::Parser>(std::move(pipe_handle), 0)); + parser->set_disconnect_handler(std::move(connection_error_handler_)); } -UniqueParserPtr ParserSandboxSetupHooks::TakeParserPtr() { - return std::move(parser_ptr_); +RemoteParserPtr ParserSandboxSetupHooks::TakeParserRemote() { + return std::move(parser_); } ResultCode SpawnParserSandbox( scoped_refptr<MojoTaskRunner> mojo_task_runner, const SandboxConnectionErrorCallback& connection_error_callback, - UniqueParserPtr* parser_ptr) { + RemoteParserPtr* parser) { auto error_handler = base::BindOnce(connection_error_callback, SandboxType::kParser); ParserSandboxSetupHooks setup_hooks(mojo_task_runner, std::move(error_handler)); ResultCode result_code = SpawnSandbox(&setup_hooks, SandboxType::kParser); - *parser_ptr = setup_hooks.TakeParserPtr(); + *parser = setup_hooks.TakeParserRemote(); return result_code; }
diff --git a/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.h b/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.h index f825d55b5..c9414589 100644 --- a/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.h +++ b/chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.h
@@ -8,17 +8,18 @@ #include <memory> #include "base/command_line.h" -#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h" #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" #include "chrome/chrome_cleaner/ipc/sandbox.h" +#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "components/chrome_cleaner/public/constants/result_codes.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/message_pipe.h" namespace chrome_cleaner { -using UniqueParserPtr = - std::unique_ptr<mojom::ParserPtr, base::OnTaskRunnerDeleter>; +using RemoteParserPtr = + std::unique_ptr<mojo::Remote<mojom::Parser>, base::OnTaskRunnerDeleter>; // Hooks to spawn a new sandboxed Parser process and bind a Mojo interface // pointer to the sandboxed implementation. @@ -28,31 +29,31 @@ base::OnceClosure connection_error_handler); ~ParserSandboxSetupHooks() override; - // Transfers ownership of |parser_ptr_| to the caller. - UniqueParserPtr TakeParserPtr(); + // Transfers ownership of |parser_| to the caller. + RemoteParserPtr TakeParserRemote(); // SandboxSetupHooks ResultCode UpdateSandboxPolicy(sandbox::TargetPolicy* policy, base::CommandLine* command_line) override; private: - void BindParserPtr(mojo::ScopedMessagePipeHandle pipe_handle, - mojom::ParserPtr* parser_ptr); + void BindParserRemote(mojo::ScopedMessagePipeHandle pipe_handle, + mojo::Remote<mojom::Parser>* parser); scoped_refptr<MojoTaskRunner> mojo_task_runner_; base::OnceClosure connection_error_handler_; - UniqueParserPtr parser_ptr_; + RemoteParserPtr parser_; DISALLOW_COPY_AND_ASSIGN(ParserSandboxSetupHooks); }; // Spawn a sandboxed process with type kParser, and return the bound -// |parser_ptr|. +// |parser|. ResultCode SpawnParserSandbox( scoped_refptr<MojoTaskRunner> mojo_task_runner, const SandboxConnectionErrorCallback& connection_error_callback, - UniqueParserPtr* parser_ptr); + RemoteParserPtr* parser); } // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/parsers/json_parser/json_splicer_unittest.cc b/chrome/chrome_cleaner/parsers/json_parser/json_splicer_unittest.cc index 117f505..81e1115e 100644 --- a/chrome/chrome_cleaner/parsers/json_parser/json_splicer_unittest.cc +++ b/chrome/chrome_cleaner/parsers/json_parser/json_splicer_unittest.cc
@@ -13,11 +13,11 @@ #include "base/synchronization/waitable_event.h" #include "base/test/test_timeouts.h" #include "base/values.h" -#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" +#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.h" #include "chrome/chrome_cleaner/parsers/target/parser_impl.h" -#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/remote.h" #include "testing/gtest/include/gtest/gtest.h" namespace chrome_cleaner { @@ -62,24 +62,25 @@ public: JsonSplicerImplTest() : task_runner_(MojoTaskRunner::Create()), - parser_ptr_(new mojom::ParserPtr(), - base::OnTaskRunnerDeleter(task_runner_)), + parser_(new mojo::Remote<mojom::Parser>(), + base::OnTaskRunnerDeleter(task_runner_)), parser_impl_(nullptr, base::OnTaskRunnerDeleter(task_runner_)), - sandboxed_json_parser_(task_runner_.get(), parser_ptr_.get()) { - task_runner_->PostTask( - FROM_HERE, BindOnce(BindParser, parser_ptr_.get(), &parser_impl_)); + sandboxed_json_parser_(task_runner_.get(), parser_.get()) { + task_runner_->PostTask(FROM_HERE, + BindOnce(BindParser, parser_.get(), &parser_impl_)); } protected: static void BindParser( - mojom::ParserPtr* json_parser, + mojo::Remote<mojom::Parser>* json_parser, std::unique_ptr<ParserImpl, base::OnTaskRunnerDeleter>* parser_impl) { - parser_impl->reset( - new ParserImpl(mojo::MakeRequest(json_parser), base::DoNothing())); + parser_impl->reset(new ParserImpl(json_parser->BindNewPipeAndPassReceiver(), + base::DoNothing())); } scoped_refptr<MojoTaskRunner> task_runner_; - std::unique_ptr<mojom::ParserPtr, base::OnTaskRunnerDeleter> parser_ptr_; + std::unique_ptr<mojo::Remote<mojom::Parser>, base::OnTaskRunnerDeleter> + parser_; std::unique_ptr<ParserImpl, base::OnTaskRunnerDeleter> parser_impl_; SandboxedJsonParser sandboxed_json_parser_; };
diff --git a/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.cc b/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.cc index 82808da..442d74a 100644 --- a/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.cc +++ b/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.cc
@@ -4,23 +4,25 @@ #include "chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.h" +#include <utility> + #include "base/bind.h" namespace chrome_cleaner { SandboxedJsonParser::SandboxedJsonParser(MojoTaskRunner* mojo_task_runner, - mojom::ParserPtr* parser_ptr) - : mojo_task_runner_(mojo_task_runner), parser_ptr_(parser_ptr) {} + mojo::Remote<mojom::Parser>* parser) + : mojo_task_runner_(mojo_task_runner), parser_(parser) {} void SandboxedJsonParser::Parse(const std::string& json, ParseDoneCallback callback) { mojo_task_runner_->PostTask( FROM_HERE, base::BindOnce( - [](mojom::ParserPtr* parser_ptr, const std::string& json, - ParseDoneCallback callback) { - (*parser_ptr)->ParseJson(json, std::move(callback)); + [](mojo::Remote<mojom::Parser>* parser, + const std::string& json, ParseDoneCallback callback) { + (*parser)->ParseJson(json, std::move(callback)); }, - parser_ptr_, json, std::move(callback))); + parser_, json, std::move(callback))); } } // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.h b/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.h index 3fc6583..189991b 100644 --- a/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.h +++ b/chrome/chrome_cleaner/parsers/json_parser/sandboxed_json_parser.h
@@ -5,24 +5,25 @@ #ifndef CHROME_CHROME_CLEANER_PARSERS_JSON_PARSER_SANDBOXED_JSON_PARSER_H_ #define CHROME_CHROME_CLEANER_PARSERS_JSON_PARSER_SANDBOXED_JSON_PARSER_H_ -#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" +#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/parsers/json_parser/json_parser_api.h" +#include "mojo/public/cpp/bindings/remote.h" namespace chrome_cleaner { // An implementation of JsonParserAPI to wrap a MojoTaskRunner and -// JsonParserPtr. Parses via |parser_ptr_| on the |mojo_task_runner_|. +// JsonParserPtr. Parses via |parser_| on the |mojo_task_runner_|. // TODO(joenotcharles): Move this class to chrome_cleaner/parsers/broker. class SandboxedJsonParser : public JsonParserAPI { public: SandboxedJsonParser(MojoTaskRunner* mojo_task_runner, - mojom::ParserPtr* parser_ptr); + mojo::Remote<mojom::Parser>* parser); void Parse(const std::string& json, ParseDoneCallback callback) override; private: MojoTaskRunner* mojo_task_runner_; - mojom::ParserPtr* parser_ptr_; + mojo::Remote<mojom::Parser>* parser_; }; } // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc index eb16eb9..d4d603b 100644 --- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc +++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc
@@ -17,14 +17,15 @@ #include "base/win/scoped_handle.h" #include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/parsers/parser_utils/parse_tasks_remaining_counter.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/platform_handle.h" namespace chrome_cleaner { SandboxedShortcutParser::SandboxedShortcutParser( MojoTaskRunner* mojo_task_runner, - mojom::ParserPtr* parser_ptr) - : mojo_task_runner_(mojo_task_runner), parser_ptr_(parser_ptr) {} + mojo::Remote<mojom::Parser>* parser) + : mojo_task_runner_(mojo_task_runner), parser_(parser) {} void SandboxedShortcutParser::ParseShortcut( base::win::ScopedHandle shortcut_handle, @@ -32,12 +33,11 @@ mojo_task_runner_->PostTask( FROM_HERE, base::BindOnce( - [](mojom::ParserPtr* parser_ptr, mojo::ScopedHandle handle, + [](mojo::Remote<mojom::Parser>* parser, mojo::ScopedHandle handle, mojom::Parser::ParseShortcutCallback callback) { - (*parser_ptr) - ->ParseShortcut(std::move(handle), std::move(callback)); + (*parser)->ParseShortcut(std::move(handle), std::move(callback)); }, - parser_ptr_, mojo::WrapPlatformFile(shortcut_handle.Take()), + parser_, mojo::WrapPlatformFile(shortcut_handle.Take()), std::move(callback))); }
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h index a5a0ca2..651cb90b 100644 --- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h +++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h
@@ -8,18 +8,19 @@ #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/win/scoped_handle.h" -#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" +#include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" #include "chrome/chrome_cleaner/os/file_path_set.h" #include "chrome/chrome_cleaner/parsers/parser_utils/parse_tasks_remaining_counter.h" #include "chrome/chrome_cleaner/parsers/shortcut_parser/broker/shortcut_parser_api.h" +#include "mojo/public/cpp/bindings/remote.h" namespace chrome_cleaner { class SandboxedShortcutParser : public ShortcutParserAPI { public: SandboxedShortcutParser(MojoTaskRunner* mojo_task_runner, - mojom::ParserPtr* parser_ptr); + mojo::Remote<mojom::Parser>* parser); // ShortcutParserAPI void FindAndParseChromeShortcutsInFoldersAsync( @@ -48,7 +49,7 @@ base::Lock lock_; MojoTaskRunner* mojo_task_runner_; - mojom::ParserPtr* parser_ptr_; + mojo::Remote<mojom::Parser>* parser_; }; } // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc index 64ac91e..5182356 100644 --- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc +++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc
@@ -36,7 +36,7 @@ class SandboxedShortcutParserTest : public base::MultiProcessTest { public: SandboxedShortcutParserTest() - : parser_ptr_(nullptr, base::OnTaskRunnerDeleter(nullptr)), + : parser_(nullptr, base::OnTaskRunnerDeleter(nullptr)), temp_dirs_with_chrome_lnk_(kDirQuantity) {} void SetUp() override { @@ -48,9 +48,9 @@ RESULT_CODE_SUCCESS, StartSandboxTarget(MakeCmdLine("SandboxedShortcutParserTargetMain"), &setup_hooks, SandboxType::kTest)); - parser_ptr_ = setup_hooks.TakeParserPtr(); + parser_ = setup_hooks.TakeParserRemote(); shortcut_parser_ = std::make_unique<SandboxedShortcutParser>( - mojo_task_runner_.get(), parser_ptr_.get()); + mojo_task_runner_.get(), parser_.get()); ASSERT_TRUE(temp_dir_without_chrome_lnk_.CreateUniqueTempDir()); ASSERT_TRUE(base::CreateTemporaryFileInDir( @@ -87,7 +87,7 @@ size_t shortcut_quantity_ = 0; scoped_refptr<MojoTaskRunner> mojo_task_runner_; - UniqueParserPtr parser_ptr_; + RemoteParserPtr parser_; std::unique_ptr<SandboxedShortcutParser> shortcut_parser_; FilePathSet fake_chrome_exe_file_path_set_;
diff --git a/chrome/chrome_cleaner/parsers/target/parser_impl.cc b/chrome/chrome_cleaner/parsers/target/parser_impl.cc index b501230..5f9aa238 100644 --- a/chrome/chrome_cleaner/parsers/target/parser_impl.cc +++ b/chrome/chrome_cleaner/parsers/target/parser_impl.cc
@@ -4,6 +4,8 @@ #include "chrome/chrome_cleaner/parsers/target/parser_impl.h" +#include <utility> + #include "base/json/json_reader.h" #include "base/values.h" #include "base/win/scoped_handle.h" @@ -12,10 +14,10 @@ namespace chrome_cleaner { -ParserImpl::ParserImpl(mojom::ParserRequest request, +ParserImpl::ParserImpl(mojo::PendingReceiver<mojom::Parser> receiver, base::OnceClosure connection_error_handler) - : binding_(this, std::move(request)) { - binding_.set_connection_error_handler(std::move(connection_error_handler)); + : receiver_(this, std::move(receiver)) { + receiver_.set_disconnect_handler(std::move(connection_error_handler)); } ParserImpl::~ParserImpl() = default;
diff --git a/chrome/chrome_cleaner/parsers/target/parser_impl.h b/chrome/chrome_cleaner/parsers/target/parser_impl.h index d774de1..b9a1d80 100644 --- a/chrome/chrome_cleaner/parsers/target/parser_impl.h +++ b/chrome/chrome_cleaner/parsers/target/parser_impl.h
@@ -6,13 +6,14 @@ #define CHROME_CHROME_CLEANER_PARSERS_TARGET_PARSER_IMPL_H_ #include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" namespace chrome_cleaner { class ParserImpl : public mojom::Parser { public: - explicit ParserImpl(mojom::ParserRequest request, + explicit ParserImpl(mojo::PendingReceiver<mojom::Parser> receiver, base::OnceClosure connection_error_handler); ~ParserImpl() override; @@ -25,7 +26,7 @@ ParserImpl::ParseShortcutCallback callback) override; private: - mojo::Binding<mojom::Parser> binding_; + mojo::Receiver<mojom::Parser> receiver_; }; } // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc b/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc index 89b52d81..fda63a0 100644 --- a/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc +++ b/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc
@@ -22,7 +22,7 @@ #include "chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h" #include "chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.h" #include "chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.h" -#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/platform_handle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,11 +41,11 @@ public: ParserImplTest() : task_runner_(MojoTaskRunner::Create()), - parser_ptr_(new mojom::ParserPtr(), - base::OnTaskRunnerDeleter(task_runner_)), + parser_(new mojo::Remote<mojom::Parser>(), + base::OnTaskRunnerDeleter(task_runner_)), parser_impl_(nullptr, base::OnTaskRunnerDeleter(task_runner_)), - sandboxed_json_parser_(task_runner_.get(), parser_ptr_.get()), - shortcut_parser_(task_runner_.get(), parser_ptr_.get()) {} + sandboxed_json_parser_(task_runner_.get(), parser_.get()), + shortcut_parser_(task_runner_.get(), parser_.get()) {} void SetUp() override { BindParser(); @@ -59,17 +59,18 @@ task_runner_->PostTask( FROM_HERE, base::BindOnce( - [](mojom::ParserPtr* parser, + [](mojo::Remote<mojom::Parser>* parser, std::unique_ptr<ParserImpl, base::OnTaskRunnerDeleter>* parser_impl) { - parser_impl->reset( - new ParserImpl(mojo::MakeRequest(parser), base::DoNothing())); + parser_impl->reset(new ParserImpl( + parser->BindNewPipeAndPassReceiver(), base::DoNothing())); }, - parser_ptr_.get(), &parser_impl_)); + parser_.get(), &parser_impl_)); } scoped_refptr<MojoTaskRunner> task_runner_; - std::unique_ptr<mojom::ParserPtr, base::OnTaskRunnerDeleter> parser_ptr_; + std::unique_ptr<mojo::Remote<mojom::Parser>, base::OnTaskRunnerDeleter> + parser_; std::unique_ptr<ParserImpl, base::OnTaskRunnerDeleter> parser_impl_; SandboxedJsonParser sandboxed_json_parser_;
diff --git a/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc b/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc index 6ca95e1..ec06298f 100644 --- a/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc +++ b/chrome/chrome_cleaner/parsers/target/sandbox_setup.cc
@@ -14,6 +14,7 @@ #include "chrome/chrome_cleaner/os/early_exit.h" #include "chrome/chrome_cleaner/parsers/target/parser_impl.h" #include "components/chrome_cleaner/public/constants/result_codes.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" namespace chrome_cleaner { @@ -37,7 +38,8 @@ // SandboxTargetHooks ResultCode TargetDroppedPrivileges( const base::CommandLine& command_line) override { - mojom::ParserRequest request(ExtractSandboxMessagePipe(command_line)); + mojo::PendingReceiver<mojom::Parser> receiver( + ExtractSandboxMessagePipe(command_line)); // This loop will run forever. Once the communication channel with the // broker process is broken, mojo error handler will abort this process. @@ -45,14 +47,14 @@ mojo_task_runner_->PostTask( FROM_HERE, base::BindOnce(&ParserSandboxTargetHooks::CreateParserImpl, - base::Unretained(this), base::Passed(&request))); + base::Unretained(this), base::Passed(&receiver))); run_loop.Run(); return RESULT_CODE_SUCCESS; } private: - void CreateParserImpl(mojom::ParserRequest request) { - parser_impl_ = std::make_unique<ParserImpl>(std::move(request), + void CreateParserImpl(mojo::PendingReceiver<mojom::Parser> receiver) { + parser_impl_ = std::make_unique<ParserImpl>(std::move(receiver), base::BindOnce(&EarlyExit, 1)); }
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 031a22b3..df65c42 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -698,6 +698,12 @@ const base::Feature kSoundContentSetting{"SoundContentSetting", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables or defaults splittup up server (not proxy) entries in the +// HttpAuthCache. +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kSplitAuthCacheByNetworkIsolationKey{ + "SplitAuthCacheByNetworkIsolationKey", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables filtering URLs by suffix to include subresources that look // like image resources for compression. For example, // http://chromium.org/image.jpg would be included.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index a964995..c428e4a6 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -423,6 +423,9 @@ extern const base::Feature kSoundContentSetting; COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kSplitAuthCacheByNetworkIsolationKey; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSubresourceRedirectIncludedMediaSuffixes; #if !defined(OS_ANDROID)
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl index 94d99b68..d8f2349d 100644 --- a/chrome/common/extensions/api/autotest_private.idl +++ b/chrome/common/extensions/api/autotest_private.idl
@@ -391,6 +391,9 @@ static void getAllEnterprisePolicies( AllEnterprisePoliciesCallback callback); + // Refreshes the Enterprise Policies. + static void refreshEnterprisePolicies(VoidCallback callback); + // Simulates a memory access bug for asan testing. static void simulateAsanMemoryBug();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 492f8e7e..382ed88 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1060,7 +1060,6 @@ "../browser/prefetch/prefetch_browsertest.cc", "../browser/prefs/pref_functional_browsertest.cc", "../browser/prefs/pref_service_browsertest.cc", - "../browser/prefs/synced_pref_change_registrar_browsertest.cc", "../browser/prefs/tracked/pref_hash_browsertest.cc", "../browser/prerender/prerender_browsertest.cc", "../browser/prerender/prerender_nostate_prefetch_browsertest.cc", @@ -1120,6 +1119,7 @@ "../browser/sessions/tab_restore_service_load_waiter.cc", "../browser/sessions/tab_restore_service_load_waiter.h", "../browser/sharing/click_to_call/click_to_call_browsertest.cc", + "../browser/sharing/shared_clipboard/shared_clipboard_browsertest.cc", "../browser/sharing/sharing_browsertest.cc", "../browser/sharing/sharing_browsertest.h", "../browser/signin/consistency_cookie_browsertest.cc", @@ -2095,6 +2095,7 @@ "../browser/chromeos/input_method/textinput_test_helper.h", "../browser/chromeos/lock_screen_apps/note_taking_browsertest.cc", "../browser/chromeos/logging_browsertest.cc", + "../browser/chromeos/login/accessibility_browsertest.cc", "../browser/chromeos/login/active_directory_login_browsertest.cc", "../browser/chromeos/login/arc_terms_of_service_browsertest.cc", "../browser/chromeos/login/auto_launched_kiosk_browsertest.cc", @@ -5641,6 +5642,7 @@ "../browser/ui/views/passwords/password_bubble_interactive_uitest.cc", "../browser/ui/views/sad_tab_view_interactive_uitest.cc", "../browser/ui/views/status_icons/status_tray_state_changer_interactive_uitest_win.cc", + "../browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc", "../browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc", "../browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h", "../browser/ui/views/tabs/tab_hover_card_bubble_view_interactive_uitest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java index 1519607b..a4045c9 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -186,11 +186,6 @@ } @Override - protected long nativeInit(Profile profile) { - return 1; - } - - @Override public void setProfile(Profile profile) {} } @@ -220,11 +215,6 @@ public void stop(boolean clear) {} @Override - protected long nativeInit(Profile profile) { - return 1; - } - - @Override public void setProfile(Profile profile) {} }
diff --git a/chrome/test/data/extensions/api_test/autotest_private/test.js b/chrome/test/data/extensions/api_test/autotest_private/test.js index bfef5e3..497dd70 100644 --- a/chrome/test/data/extensions/api_test/autotest_private/test.js +++ b/chrome/test/data/extensions/api_test/autotest_private/test.js
@@ -666,6 +666,14 @@ chrome.test.succeed(); })); }, + function refreshEnterprisePolicies() { + chrome.autotestPrivate.refreshEnterprisePolicies( + chrome.test.callbackPass(function() { + chrome.test.succeed(); + }) + ); + }, + ]; var arcPerformanceTracingTests = [
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 2e4bb8b..366df99 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -12603.0.0 \ No newline at end of file +12605.0.0 \ No newline at end of file
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 98c4fd5..1507c85 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -183,7 +183,7 @@ // Enables or disables the scrollable shelf. const base::Feature kShelfScrollable{"ShelfScrollable", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Enables or disables the shelf hotseat. const base::Feature kShelfHotseat{"ShelfHotseat",
diff --git a/chromeos/constants/chromeos_paths.cc b/chromeos/constants/chromeos_paths.cc index 2388ae8..152fc44 100644 --- a/chromeos/constants/chromeos_paths.cc +++ b/chromeos/constants/chromeos_paths.cc
@@ -34,6 +34,9 @@ const base::FilePath::CharType kUpdateRebootNeededUptimeFile[] = FILE_PATH_LITERAL("/run/chrome/update_reboot_needed_uptime"); +const base::FilePath::CharType kStartupCustomizationManifestFile[] = + FILE_PATH_LITERAL("/opt/oem/etc/startup_manifest.json"); + const base::FilePath::CharType kDeviceLocalAccountExtensionDir[] = FILE_PATH_LITERAL("/var/cache/device_local_account_extensions"); @@ -75,6 +78,9 @@ case FILE_UPDATE_REBOOT_NEEDED_UPTIME: *result = base::FilePath(kUpdateRebootNeededUptimeFile); break; + case FILE_STARTUP_CUSTOMIZATION_MANIFEST: + *result = base::FilePath(kStartupCustomizationManifestFile); + break; case DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS: *result = base::FilePath(kDeviceLocalAccountExtensionDir); break;
diff --git a/chromeos/constants/chromeos_paths.h b/chromeos/constants/chromeos_paths.h index 0bf26b08..86c49eb 100644 --- a/chromeos/constants/chromeos_paths.h +++ b/chromeos/constants/chromeos_paths.h
@@ -29,6 +29,8 @@ // store the uptime at which an update // became necessary. The file should be // cleared on boot. + FILE_STARTUP_CUSTOMIZATION_MANIFEST, // Path to OEM partner startup + // customization manifest. DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS, // Directory under which a cache of // force-installed extensions is // maintained for each device-local
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn index 95d22b7..6239a07 100644 --- a/chromeos/dbus/BUILD.gn +++ b/chromeos/dbus/BUILD.gn
@@ -113,8 +113,6 @@ "fake_virtual_file_provider_client.h", "fake_vm_plugin_dispatcher_client.cc", "fake_vm_plugin_dispatcher_client.h", - "fake_wilco_dtc_supportd_client.cc", - "fake_wilco_dtc_supportd_client.h", "gnubby_client.cc", "gnubby_client.h", "image_burner_client.cc", @@ -144,8 +142,6 @@ "virtual_file_provider_client.h", "vm_plugin_dispatcher_client.cc", "vm_plugin_dispatcher_client.h", - "wilco_dtc_supportd_client.cc", - "wilco_dtc_supportd_client.h", ] }
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc index f6c3bc4..445c832 100644 --- a/chromeos/dbus/dbus_clients_browser.cc +++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -39,7 +39,6 @@ #include "chromeos/dbus/fake_smb_provider_client.h" #include "chromeos/dbus/fake_virtual_file_provider_client.h" #include "chromeos/dbus/fake_vm_plugin_dispatcher_client.h" -#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h" #include "chromeos/dbus/gnubby_client.h" #include "chromeos/dbus/image_burner_client.h" #include "chromeos/dbus/image_loader_client.h" @@ -51,7 +50,6 @@ #include "chromeos/dbus/update_engine_client.h" #include "chromeos/dbus/virtual_file_provider_client.h" #include "chromeos/dbus/vm_plugin_dispatcher_client.h" -#include "chromeos/dbus/wilco_dtc_supportd_client.h" namespace chromeos { @@ -110,8 +108,6 @@ CREATE_DBUS_CLIENT(VirtualFileProviderClient, use_real_clients); vm_plugin_dispatcher_client_ = CREATE_DBUS_CLIENT(VmPluginDispatcherClient, use_real_clients); - wilco_dtc_supportd_client_ = - CREATE_DBUS_CLIENT(WilcoDtcSupportdClient, use_real_clients); } DBusClientsBrowser::~DBusClientsBrowser() = default; @@ -141,7 +137,6 @@ update_engine_client_->Init(system_bus); virtual_file_provider_client_->Init(system_bus); vm_plugin_dispatcher_client_->Init(system_bus); - wilco_dtc_supportd_client_->Init(system_bus); } } // namespace chromeos
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h index bc7e1f29..02ea4eb 100644 --- a/chromeos/dbus/dbus_clients_browser.h +++ b/chromeos/dbus/dbus_clients_browser.h
@@ -38,7 +38,6 @@ class UpdateEngineClient; class VirtualFileProviderClient; class VmPluginDispatcherClient; -class WilcoDtcSupportdClient; // D-Bus clients used only in the browser process. // TODO(jamescook): Move this under //chrome/browser. http://crbug.com/647367 @@ -77,7 +76,6 @@ std::unique_ptr<UpdateEngineClient> update_engine_client_; std::unique_ptr<VirtualFileProviderClient> virtual_file_provider_client_; std::unique_ptr<VmPluginDispatcherClient> vm_plugin_dispatcher_client_; - std::unique_ptr<WilcoDtcSupportdClient> wilco_dtc_supportd_client_; DISALLOW_COPY_AND_ASSIGN(DBusClientsBrowser); };
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc index b47d7b0..8d4443b5 100644 --- a/chromeos/dbus/dbus_thread_manager.cc +++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -240,11 +240,6 @@ : nullptr; } -WilcoDtcSupportdClient* DBusThreadManager::GetWilcoDtcSupportdClient() { - return clients_browser_ ? clients_browser_->wilco_dtc_supportd_client_.get() - : nullptr; -} - VmPluginDispatcherClient* DBusThreadManager::GetVmPluginDispatcherClient() { return clients_browser_ ? clients_browser_->vm_plugin_dispatcher_client_.get() : nullptr;
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h index 3141542..816a8ad 100644 --- a/chromeos/dbus/dbus_thread_manager.h +++ b/chromeos/dbus/dbus_thread_manager.h
@@ -56,7 +56,6 @@ class UpdateEngineClient; class VirtualFileProviderClient; class VmPluginDispatcherClient; -class WilcoDtcSupportdClient; // THIS CLASS IS BEING DEPRECATED. See README.md for guidelines and // https://crbug.com/647367 for details. @@ -138,7 +137,6 @@ UpdateEngineClient* GetUpdateEngineClient(); VirtualFileProviderClient* GetVirtualFileProviderClient(); VmPluginDispatcherClient* GetVmPluginDispatcherClient(); - WilcoDtcSupportdClient* GetWilcoDtcSupportdClient(); // DEPRECATED, DO NOT USE. The static getter for each of these classes should // be used instead. TODO(stevenjb): Remove. https://crbug.com/948390.
diff --git a/chromeos/dbus/wilco_dtc_supportd_client.h b/chromeos/dbus/wilco_dtc_supportd_client.h deleted file mode 100644 index e4c9cdb..0000000 --- a/chromeos/dbus/wilco_dtc_supportd_client.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2018 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 CHROMEOS_DBUS_WILCO_DTC_SUPPORTD_CLIENT_H_ -#define CHROMEOS_DBUS_WILCO_DTC_SUPPORTD_CLIENT_H_ - -#include <memory> - -#include "base/component_export.h" -#include "base/files/scoped_file.h" -#include "base/macros.h" -#include "chromeos/dbus/dbus_client.h" -#include "chromeos/dbus/dbus_method_call_status.h" -#include "dbus/object_proxy.h" - -namespace chromeos { - -class COMPONENT_EXPORT(CHROMEOS_DBUS) WilcoDtcSupportdClient - : public DBusClient { - public: - // Factory function. - static std::unique_ptr<WilcoDtcSupportdClient> Create(); - - // Registers |callback| to run when the wilco_dtc_supportd service becomes - // available. - virtual void WaitForServiceToBeAvailable( - WaitForServiceToBeAvailableCallback callback) = 0; - - // Bootstrap the Mojo connection between Chrome and the wilco_dtc_supportd - // daemon. |fd| is the file descriptor with the child end of the Mojo pipe. - virtual void BootstrapMojoConnection(base::ScopedFD fd, - VoidDBusMethodCallback callback) = 0; - - protected: - // Create() should be used instead. - WilcoDtcSupportdClient(); - - private: - DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdClient); -}; - -} // namespace chromeos - -#endif // CHROMEOS_DBUS_WILCO_DTC_SUPPORTD_CLIENT_H_
diff --git a/chromeos/services/ime/ime_service.cc b/chromeos/services/ime/ime_service.cc index d0fd3e6..098d5ce 100644 --- a/chromeos/services/ime/ime_service.cc +++ b/chromeos/services/ime/ime_service.cc
@@ -33,7 +33,8 @@ } // namespace ImeService::ImeService(mojo::PendingReceiver<mojom::ImeService> receiver) - : receiver_(this, std::move(receiver)) { + : receiver_(this, std::move(receiver)), + main_task_runner_(base::SequencedTaskRunnerHandle::Get()) { input_engine_ = chromeos::features::IsImeDecoderWithSandboxEnabled() ? std::make_unique<DecoderEngine>(this) : std::make_unique<InputEngine>(); @@ -77,7 +78,7 @@ } const char* ImeService::GetImeGlobalDir() { - // Global IME data dir will not be supported yet. + // Global IME data is supported yet. return ""; } @@ -86,10 +87,11 @@ } void ImeService::RunInMainSequence(ImeSequencedTask task, int task_id) { - // Always run tasks on current SequencedTaskRunner. - // It's necessary for making any call on a bound Mojo Remote. - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(task, task_id)); + // This helps ensure that tasks run in the **main** SequencedTaskRunner. + // E.g. the Mojo Remotes are bound on the main_task_runner_, so that any task + // invoked Mojo call from other threads (sequences) should be posted to + // main_task_runner_ by this function. + main_task_runner_->PostTask(FROM_HERE, base::BindOnce(task, task_id)); } int ImeService::SimpleDownloadToFile(const char* url,
diff --git a/chromeos/services/ime/ime_service.h b/chromeos/services/ime/ime_service.h index 3c05ff31..3879f638 100644 --- a/chromeos/services/ime/ime_service.h +++ b/chromeos/services/ime/ime_service.h
@@ -60,6 +60,7 @@ const base::FilePath& file); mojo::Receiver<mojom::ImeService> receiver_; + scoped_refptr<base::SequencedTaskRunner> main_task_runner_; // For the duration of this service lifetime, there should be only one // input engine instance.
diff --git a/components/arc/camera/arc_camera_bridge.cc b/components/arc/camera/arc_camera_bridge.cc index e1c6e4c..7bf7f08 100644 --- a/components/arc/camera/arc_camera_bridge.cc +++ b/components/arc/camera/arc_camera_bridge.cc
@@ -135,7 +135,7 @@ } void ArcCameraBridge::RegisterCameraHalClient( - cros::mojom::CameraHalClientPtr client) { + mojo::PendingRemote<cros::mojom::CameraHalClient> client) { media::CameraHalDispatcherImpl::GetInstance()->RegisterClient( std::move(client)); }
diff --git a/components/arc/camera/arc_camera_bridge.h b/components/arc/camera/arc_camera_bridge.h index e327a71..d72430f 100644 --- a/components/arc/camera/arc_camera_bridge.h +++ b/components/arc/camera/arc_camera_bridge.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "components/arc/mojom/camera.mojom.h" #include "components/keyed_service/core/keyed_service.h" +#include "mojo/public/cpp/bindings/pending_remote.h" namespace content { class BrowserContext; @@ -34,7 +35,8 @@ // mojom::CameraHost overrides: void StartCameraService(StartCameraServiceCallback callback) override; - void RegisterCameraHalClient(cros::mojom::CameraHalClientPtr client) override; + void RegisterCameraHalClient( + mojo::PendingRemote<cros::mojom::CameraHalClient> client) override; private: class PendingStartCameraServiceResult;
diff --git a/components/arc/mojom/camera.mojom b/components/arc/mojom/camera.mojom index 04106e6..6437d71 100644 --- a/components/arc/mojom/camera.mojom +++ b/components/arc/mojom/camera.mojom
@@ -99,7 +99,8 @@ StartCameraService@0() => (CameraService service); // Registers the camera HAL client. Used by camera HAL v3. - [MinVersion=2] RegisterCameraHalClient@1(cros.mojom.CameraHalClient client); + [MinVersion=2] RegisterCameraHalClient@1( + pending_remote<cros.mojom.CameraHalClient> client); }; // Next method ID: 1
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc index 60b2413..e5095c1 100644 --- a/components/autofill/content/renderer/password_generation_agent.cc +++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -307,6 +307,12 @@ UserTriggeredGeneratePasswordCallback callback) { if (SetUpUserTriggeredGeneration()) { LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP); + // If the field is not |type=password|, the list of suggestions + // should not be populated with passwords to avoid filling them in a + // clear-text field. + // |IsPasswordFieldForAutofill()| is deliberately not used. + bool is_generation_element_password_type = + current_generation_item_->generation_element_.IsPasswordField(); autofill::password_generation::PasswordGenerationUIData password_generation_ui_data( render_frame()->ElementBoundsInWindow( @@ -316,6 +322,7 @@ .Utf16(), current_generation_item_->generation_element_ .UniqueRendererFormControlId(), + is_generation_element_password_type, GetTextDirectionForElement( current_generation_item_->generation_element_), current_generation_item_->form_); @@ -511,6 +518,12 @@ DCHECK(current_generation_item_); DCHECK(!current_generation_item_->generation_element_.IsNull()); LogMessage(Logger::STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE); + // If the field is not |type=password|, the list of suggestions + // should not be populated with passwordS to avoid filling them in a + // clear-text field. + // |IsPasswordFieldForAutofill()| is deliberately not used. + bool is_generation_element_password_type = + current_generation_item_->generation_element_.IsPasswordField(); autofill::password_generation::PasswordGenerationUIData password_generation_ui_data( render_frame()->ElementBoundsInWindow( @@ -520,6 +533,7 @@ .Utf16(), current_generation_item_->generation_element_ .UniqueRendererFormControlId(), + is_generation_element_password_type, GetTextDirectionForElement( current_generation_item_->generation_element_), current_generation_item_->form_);
diff --git a/components/autofill/core/common/mojom/autofill_types.mojom b/components/autofill/core/common/mojom/autofill_types.mojom index 4ab37ae..08792489 100644 --- a/components/autofill/core/common/mojom/autofill_types.mojom +++ b/components/autofill/core/common/mojom/autofill_types.mojom
@@ -214,6 +214,7 @@ int32 max_length; mojo_base.mojom.String16 generation_element; uint32 generation_element_id; + bool is_generation_element_password_type; mojo_base.mojom.TextDirection text_direction; PasswordForm password_form; };
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc index 117da5b..3962a51 100644 --- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc +++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -223,6 +223,8 @@ out->max_length = data.max_length(); out->generation_element_id = data.generation_element_id(); + out->is_generation_element_password_type = + data.is_generation_element_password_type(); if (!data.ReadGenerationElement(&out->generation_element) || !data.ReadTextDirection(&out->text_direction) ||
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h index a4acca8..a26fbd2 100644 --- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h +++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -408,6 +408,11 @@ return r.generation_element_id; } + static bool is_generation_element_password_type( + const autofill::password_generation::PasswordGenerationUIData& r) { + return r.is_generation_element_password_type; + } + static base::i18n::TextDirection text_direction( const autofill::password_generation::PasswordGenerationUIData& r) { return r.text_direction;
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc index 4419cd3..1fd64be 100644 --- a/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc +++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
@@ -117,6 +117,7 @@ data->max_length = 20; data->generation_element = base::ASCIIToUTF16("generation_element"); data->text_direction = base::i18n::RIGHT_TO_LEFT; + data->is_generation_element_password_type = false; CreateTestPasswordForm(&data->password_form); } @@ -154,6 +155,8 @@ EXPECT_EQ(expected.bounds, actual.bounds); EXPECT_EQ(expected.max_length, actual.max_length); EXPECT_EQ(expected.generation_element, actual.generation_element); + EXPECT_EQ(expected.is_generation_element_password_type, + actual.is_generation_element_password_type); EXPECT_EQ(expected.text_direction, actual.text_direction); EXPECT_EQ(expected.password_form, actual.password_form); }
diff --git a/components/autofill/core/common/password_generation_util.cc b/components/autofill/core/common/password_generation_util.cc index 8bab183..6f89ed2 100644 --- a/components/autofill/core/common/password_generation_util.cc +++ b/components/autofill/core/common/password_generation_util.cc
@@ -17,12 +17,14 @@ int max_length, const base::string16& generation_element, uint32_t generation_element_id, + bool is_generation_element_password_type, base::i18n::TextDirection text_direction, const autofill::PasswordForm& password_form) : bounds(bounds), max_length(max_length), generation_element(generation_element), generation_element_id(generation_element_id), + is_generation_element_password_type(is_generation_element_password_type), text_direction(text_direction), password_form(password_form) {}
diff --git a/components/autofill/core/common/password_generation_util.h b/components/autofill/core/common/password_generation_util.h index 47c9f2098..c2143d1 100644 --- a/components/autofill/core/common/password_generation_util.h +++ b/components/autofill/core/common/password_generation_util.h
@@ -109,6 +109,7 @@ int max_length, const base::string16& generation_element, uint32_t generation_element_id, + bool is_generation_element_password_type, base::i18n::TextDirection text_direction, const autofill::PasswordForm& password_form); PasswordGenerationUIData(); @@ -132,6 +133,9 @@ // Renderer ID of the generation element. uint32_t generation_element_id; + // Is the generation element |type=password|. + bool is_generation_element_password_type; + // Direction of the text for |generation_element|. base::i18n::TextDirection text_direction;
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc index 15bfb05..7aff9b5 100644 --- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -1050,11 +1050,14 @@ SelectOption(selector, "two").proto_status()); } -IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, SelectOptionInIframe) { - Selector selector; - selector.selectors.emplace_back("#iframe"); - selector.selectors.emplace_back("select[name=state]"); - EXPECT_EQ(ACTION_APPLIED, SelectOption(selector, "NY").proto_status()); +IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, SelectOptionInIFrame) { + Selector select_selector; + + // IFrame. + select_selector.selectors.clear(); + select_selector.selectors.emplace_back("#iframe"); + select_selector.selectors.emplace_back("select[name=state]"); + EXPECT_EQ(ACTION_APPLIED, SelectOption(select_selector, "NY").proto_status()); const std::string javascript = R"( let iframe = document.querySelector("iframe").contentDocument; @@ -1062,16 +1065,46 @@ select.options[select.selectedIndex].label; )"; EXPECT_EQ("NY", content::EvalJs(shell(), javascript)); + + // OOPIF. + // Checking elements through EvalJs in OOPIF is blocked by cross-site. + select_selector.selectors.clear(); + select_selector.selectors.emplace_back("#iframeExternal"); + select_selector.selectors.emplace_back("select[name=pet]"); + EXPECT_EQ(ACTION_APPLIED, + SelectOption(select_selector, "Cat").proto_status()); + + Selector result_selector; + result_selector.selectors.emplace_back("#iframeExternal"); + result_selector.selectors.emplace_back("#myPet"); + GetFieldsValue({result_selector}, {"Cat"}); } IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetOuterHtml) { - Selector selector; - selector.selectors.emplace_back("#testOuterHtml"); std::string html; - ASSERT_EQ(ACTION_APPLIED, GetOuterHtml(selector, &html).proto_status()); + + // Div. + Selector div_selector; + div_selector.selectors.emplace_back("#testOuterHtml"); + ASSERT_EQ(ACTION_APPLIED, GetOuterHtml(div_selector, &html).proto_status()); EXPECT_EQ( R"(<div id="testOuterHtml"><span>Span</span><p>Paragraph</p></div>)", html); + + // IFrame. + Selector iframe_selector; + iframe_selector.selectors.emplace_back("#iframe"); + iframe_selector.selectors.emplace_back("#input"); + ASSERT_EQ(ACTION_APPLIED, + GetOuterHtml(iframe_selector, &html).proto_status()); + EXPECT_EQ(R"(<input id="input" type="text">)", html); + + // OOPIF. + Selector oopif_selector; + oopif_selector.selectors.emplace_back("#iframeExternal"); + oopif_selector.selectors.emplace_back("#divToRemove"); + ASSERT_EQ(ACTION_APPLIED, GetOuterHtml(oopif_selector, &html).proto_status()); + EXPECT_EQ(R"(<div id="divToRemove">Text</div>)", html); } IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetAndSetFieldValue) {
diff --git a/components/content_settings/core/browser/website_settings_registry.cc b/components/content_settings/core/browser/website_settings_registry.cc index e7627f3..8334e076 100644 --- a/components/content_settings/core/browser/website_settings_registry.cc +++ b/components/content_settings/core/browser/website_settings_registry.cc
@@ -203,6 +203,11 @@ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY, WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE, DESKTOP, WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO); + Register(CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, + "installed-web-app-metadata", nullptr, + WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY, + WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP, + WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO); } } // namespace content_settings
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc index e1aca34..dc447411 100644 --- a/components/content_settings/core/common/content_settings.cc +++ b/components/content_settings/core/common/content_settings.cc
@@ -79,6 +79,7 @@ {CONTENT_SETTINGS_TYPE_WAKE_LOCK_SYSTEM, 55}, {CONTENT_SETTINGS_TYPE_LEGACY_COOKIE_ACCESS, 56}, {CONTENT_SETTINGS_TYPE_NATIVE_FILE_SYSTEM_WRITE_GUARD, 57}, + {CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, 58}, }; } // namespace
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h index 8bb5011..a082aaa0 100644 --- a/components/content_settings/core/common/content_settings_types.h +++ b/components/content_settings/core/common/content_settings_types.h
@@ -172,6 +172,10 @@ // File System API. CONTENT_SETTINGS_TYPE_NATIVE_FILE_SYSTEM_WRITE_GUARD, + // Content settings for installed web apps that browsing history may be + // inferred from e.g. last update check timestamp. + CONTENT_SETTINGS_TYPE_INSTALLED_WEB_APP_METADATA, + CONTENT_SETTINGS_NUM_TYPES, };
diff --git a/components/content_settings/core/common/cookie_settings_base.cc b/components/content_settings/core/common/cookie_settings_base.cc index ef3986a..eb4304f5 100644 --- a/components/content_settings/core/common/cookie_settings_base.cc +++ b/components/content_settings/core/common/cookie_settings_base.cc
@@ -86,14 +86,6 @@ const GURL& url, const GURL& site_for_cookies, const base::Optional<url::Origin>& top_frame_origin) const { - // TODO(crbug.com/988398): top_frame_origin is not yet always available. - // Ensure that the DCHECK always passes and remove the FeatureList check. - DCHECK((!base::FeatureList::IsEnabled(kImprovedCookieControls) && - !base::FeatureList::IsEnabled( - kImprovedCookieControlsForThirdPartyCookieBlocking)) || - top_frame_origin || site_for_cookies.is_empty()) - << url << " " << site_for_cookies; - ContentSetting setting; GetCookieSettingInternal( url, top_frame_origin ? top_frame_origin->GetURL() : site_for_cookies,
diff --git a/components/dbus/menu/menu_property_list.cc b/components/dbus/menu/menu_property_list.cc index c08b367..acbc74fc 100644 --- a/components/dbus/menu/menu_property_list.cc +++ b/components/dbus/menu/menu_property_list.cc
@@ -67,7 +67,6 @@ switch (menu->GetTypeAt(i)) { case ui::MenuModel::TYPE_COMMAND: case ui::MenuModel::TYPE_HIGHLIGHTED: - case ui::MenuModel::TYPE_TITLE: // Nothing special to do. break; case ui::MenuModel::TYPE_CHECK:
diff --git a/components/dbus/menu/menu_property_list_unittest.cc b/components/dbus/menu/menu_property_list_unittest.cc index a5e9854..b02783af 100644 --- a/components/dbus/menu/menu_property_list_unittest.cc +++ b/components/dbus/menu/menu_property_list_unittest.cc
@@ -149,9 +149,6 @@ case ui::MenuModel::TYPE_COMMAND: menu->AddItem(0, label_); break; - case ui::MenuModel::TYPE_TITLE: - menu->AddTitle(label_); - break; case ui::MenuModel::TYPE_CHECK: menu->AddCheckItem(0, label_); break;
diff --git a/components/gwp_asan/client/gwp_asan.cc b/components/gwp_asan/client/gwp_asan.cc index c4d2d8db..7174c96 100644 --- a/components/gwp_asan/client/gwp_asan.cc +++ b/components/gwp_asan/client/gwp_asan.cc
@@ -36,8 +36,8 @@ namespace internal { namespace { -constexpr int kDefaultMaxAllocations = 35; -constexpr int kDefaultMaxMetadata = 150; +constexpr int kDefaultMaxAllocations = 70; +constexpr int kDefaultMaxMetadata = 255; #if defined(ARCH_CPU_64_BITS) constexpr int kDefaultTotalPages = 2048; @@ -51,17 +51,23 @@ // multiplier * range**rand // where rand is a random real number in the range [0,1). constexpr int kDefaultAllocationSamplingMultiplier = 1000; -constexpr int kDefaultAllocationSamplingRange = 64; +constexpr int kDefaultAllocationSamplingRange = 16; -constexpr double kDefaultProcessSamplingProbability = 0.2; +constexpr double kDefaultProcessSamplingProbability = 0.015; // The multiplier to increase the ProcessSamplingProbability in scenarios where // we want to perform additional testing (e.g., on canary/dev builds). -constexpr int kDefaultProcessSamplingBoost2 = 5; +constexpr int kDefaultProcessSamplingBoost2 = 10; -const base::Feature kGwpAsanMalloc{"GwpAsanMalloc", - base::FEATURE_DISABLED_BY_DEFAULT}; +#if defined(OS_WIN) || defined(OS_MACOSX) +constexpr base::FeatureState kDefaultEnabled = base::FEATURE_ENABLED_BY_DEFAULT; +#else +constexpr base::FeatureState kDefaultEnabled = + base::FEATURE_DISABLED_BY_DEFAULT; +#endif + +const base::Feature kGwpAsanMalloc{"GwpAsanMalloc", kDefaultEnabled}; const base::Feature kGwpAsanPartitionAlloc{"GwpAsanPartitionAlloc", - base::FEATURE_DISABLED_BY_DEFAULT}; + kDefaultEnabled}; // Returns whether this process should be sampled to enable GWP-ASan. bool SampleProcess(const base::Feature& feature, bool boost_sampling) {
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc index 17058cc0..9b9fd4e 100644 --- a/components/history/core/browser/history_service.cc +++ b/components/history/core/browser/history_service.cc
@@ -62,15 +62,17 @@ using base::Time; namespace history { + namespace { -const base::Feature kHistoryServiceUsesTaskScheduler{ - "HistoryServiceUsesTaskScheduler", base::FEATURE_DISABLED_BY_DEFAULT}; - -static const char* kHistoryThreadName = "Chrome_HistoryThread"; +const char* kHistoryThreadName = "Chrome_HistoryThread"; } // namespace +// static +const base::Feature HistoryService::kHistoryServiceUsesTaskScheduler{ + "HistoryServiceUsesTaskScheduler", base::FEATURE_DISABLED_BY_DEFAULT}; + // Sends messages from the backend to us on the main thread. This must be a // separate class from the history service so that it can hold a reference to // the history service (otherwise we would have to manually AddRef and
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h index cc8ad6e..5600f42 100644 --- a/components/history/core/browser/history_service.h +++ b/components/history/core/browser/history_service.h
@@ -18,6 +18,7 @@ #include "base/callback.h" #include "base/callback_list.h" #include "base/containers/flat_set.h" +#include "base/feature_list.h" #include "base/files/file_path.h" #include "base/location.h" #include "base/logging.h" @@ -87,6 +88,8 @@ // as information about downloads. class HistoryService : public KeyedService { public: + static const base::Feature kHistoryServiceUsesTaskScheduler; + // Must call Init after construction. The empty constructor provided only for // unit tests. When using the full constructor, |history_client| may only be // null during testing, while |visit_delegate| may be null if the embedder use
diff --git a/components/password_manager/core/browser/manage_passwords_referrer.h b/components/password_manager/core/browser/manage_passwords_referrer.h index 2420893..d202ce9 100644 --- a/components/password_manager/core/browser/manage_passwords_referrer.h +++ b/components/password_manager/core/browser/manage_passwords_referrer.h
@@ -9,6 +9,11 @@ // Enumerates referrers that can trigger a navigation to the manage passwords // page. +// +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. Needs to stay in sync with +// ManagePasswordsReferrer in enums.xml. +// // A Java counterpart will be generated for this enum. // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.password_manager enum class ManagePasswordsReferrer {
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc index ef5b4ac..46b7f3e7 100644 --- a/components/password_manager/core/browser/password_autofill_manager.cc +++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include <algorithm> +#include <string> #include <utility> #include <vector> @@ -338,14 +339,16 @@ bool PasswordAutofillManager::MaybeShowPasswordSuggestionsWithGeneration( const gfx::RectF& bounds, - base::i18n::TextDirection text_direction) { + base::i18n::TextDirection text_direction, + bool show_password_suggestions) { if (!fill_data_) return false; std::vector<autofill::Suggestion> suggestions; - GetSuggestions(*fill_data_, base::string16(), page_favicon_, - true /* show_all */, true /* is_password_field */, - &suggestions); - + if (show_password_suggestions) { + GetSuggestions(*fill_data_, base::string16(), page_favicon_, + true /* show_all */, true /* is_password_field */, + &suggestions); + } // Add 'Generation' option. // The UI code will pick up an icon from the resources based on the string. autofill::Suggestion suggestion(
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h index 618b014..967615e 100644 --- a/components/password_manager/core/browser/password_autofill_manager.h +++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -6,6 +6,7 @@ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_AUTOFILL_MANAGER_H_ #include <map> +#include <memory> #include "base/callback.h" #include "base/i18n/rtl.h" @@ -85,7 +86,8 @@ // and returns false. bool MaybeShowPasswordSuggestionsWithGeneration( const gfx::RectF& bounds, - base::i18n::TextDirection text_direction); + base::i18n::TextDirection text_direction, + bool show_password_suggestions); // Called when main frame navigates. Not called for in-page navigations. void DidNavigateMainFrame();
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc index 15f27f81..a74e2931 100644 --- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc +++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -6,6 +6,8 @@ #include <memory> #include <string> +#include <utility> +#include <vector> #include "base/command_line.h" #include "base/compiler_specific.h" @@ -299,9 +301,10 @@ EXPECT_CALL(*autofill_client, HideAutofillPopup()); base::HistogramTester histograms; password_autofill_manager_->DidAcceptSuggestion( - test_username_, is_suggestion_on_password_field - ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY - : autofill::POPUP_ITEM_ID_USERNAME_ENTRY, + test_username_, + is_suggestion_on_password_field + ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY + : autofill::POPUP_ITEM_ID_USERNAME_ENTRY, 1); histograms.ExpectUniqueSample( kDropdownSelectedHistogram, @@ -735,7 +738,8 @@ gfx::RectF element_bounds; EXPECT_FALSE( password_autofill_manager_->MaybeShowPasswordSuggestionsWithGeneration( - element_bounds, base::i18n::RIGHT_TO_LEFT)); + element_bounds, base::i18n::RIGHT_TO_LEFT, + /*show_password_suggestions=*/true)); } TEST_F(PasswordAutofillManagerTest, @@ -770,7 +774,8 @@ false, PopupType::kPasswords, _)); EXPECT_TRUE( password_autofill_manager_->MaybeShowPasswordSuggestionsWithGeneration( - element_bounds, base::i18n::RIGHT_TO_LEFT)); + element_bounds, base::i18n::RIGHT_TO_LEFT, + /*show_password_suggestions=*/true)); histograms.ExpectUniqueSample( kDropdownShownHistogram, metrics_util::PasswordDropdownState::kStandardGenerate, 1); @@ -785,4 +790,39 @@ metrics_util::PasswordDropdownSelectedOption::kGenerate, 1); } +TEST_F(PasswordAutofillManagerTest, + MaybeShowPasswordSuggestionsWithOmittedCredentials) { + auto client = std::make_unique<TestPasswordManagerClient>(); + auto autofill_client = std::make_unique<MockAutofillClient>(); + InitializePasswordAutofillManager(client.get(), autofill_client.get()); + + gfx::RectF element_bounds; + autofill::PasswordFormFillData data; + data.username_field.value = test_username_; + data.password_field.value = test_password_; + data.origin = GURL("https://foo.test"); + + favicon::MockFaviconService favicon_service; + EXPECT_CALL(*client, GetFaviconService()).WillOnce(Return(&favicon_service)); + EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.origin, _, _)); + password_autofill_manager_->OnAddPasswordFillData(data); + + base::string16 generation_string = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_GENERATE_PASSWORD); + + EXPECT_CALL( + *autofill_client, + ShowAutofillPopup( + element_bounds, base::i18n::RIGHT_TO_LEFT, + AllOf(SuggestionVectorValuesAre( + ElementsAreArray(GetSuggestionList({generation_string}))), + SuggestionVectorIconsAre( + ElementsAreArray(GetIconsList({"keyIcon"})))), + false, PopupType::kPasswords, _)); + + EXPECT_TRUE( + password_autofill_manager_->MaybeShowPasswordSuggestionsWithGeneration( + element_bounds, base::i18n::RIGHT_TO_LEFT, + /*show_password_suggestions=*/false)); +} } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index 0232462..c48ff9d 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -124,11 +124,13 @@ init_status_(InitStatus::kUnknown) {} bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare, - PrefService* prefs) { + PrefService* prefs, + base::RepeatingClosure sync_enabled_or_disabled_cb) { main_task_runner_ = base::SequencedTaskRunnerHandle::Get(); DCHECK(main_task_runner_); background_task_runner_ = CreateBackgroundTaskRunner(); DCHECK(background_task_runner_); + sync_enabled_or_disabled_cb_ = std::move(sync_enabled_or_disabled_cb); #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED) prefs_ = prefs; hash_password_manager_.set_prefs(prefs); @@ -553,7 +555,7 @@ sync_bridge_.reset(new PasswordSyncBridge( std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( syncer::PASSWORDS, base::DoNothing()), - /*password_store_sync=*/this)); + /*password_store_sync=*/this, sync_enabled_or_disabled_cb_)); } else { DCHECK(!syncable_service_); syncable_service_.reset(new PasswordSyncableService(this));
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index f610fd7..3e1a077 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h
@@ -112,10 +112,11 @@ PasswordStore(); - // Reimplement this to add custom initialization. Always call this too on the - // UI thread. - virtual bool Init(const syncer::SyncableService::StartSyncFlare& flare, - PrefService* prefs); + // Always call this too on the UI thread. + bool Init( + const syncer::SyncableService::StartSyncFlare& flare, + PrefService* prefs, + base::RepeatingClosure sync_enabled_or_disabled_cb = base::DoNothing()); // RefcountedKeyedService: void ShutdownOnUIThread() override; @@ -716,6 +717,8 @@ std::unique_ptr<PasswordSyncableService> syncable_service_; std::unique_ptr<PasswordSyncBridge> sync_bridge_; + base::RepeatingClosure sync_enabled_or_disabled_cb_; + std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_; #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc index 4ec760f..26e1d17 100644 --- a/components/password_manager/core/browser/sync/password_sync_bridge.cc +++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -7,6 +7,7 @@ #include <unordered_set> #include "base/auto_reset.h" +#include "base/callback.h" #include "base/logging.h" #include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" @@ -172,9 +173,7 @@ } bool ShouldRecoverPasswordsDuringMerge() { - return base::FeatureList::IsEnabled( - features::kRecoverPasswordsForSyncUsers) && - !base::FeatureList::IsEnabled(features::kDeleteCorruptedPasswords); + return !base::FeatureList::IsEnabled(features::kDeleteCorruptedPasswords); } // A simple class for scoping a password store sync transaction. If the @@ -211,10 +210,13 @@ PasswordSyncBridge::PasswordSyncBridge( std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, - PasswordStoreSync* password_store_sync) + PasswordStoreSync* password_store_sync, + const base::RepeatingClosure& sync_enabled_or_disabled_cb) : ModelTypeSyncBridge(std::move(change_processor)), - password_store_sync_(password_store_sync) { + password_store_sync_(password_store_sync), + sync_enabled_or_disabled_cb_(sync_enabled_or_disabled_cb) { DCHECK(password_store_sync_); + DCHECK(sync_enabled_or_disabled_cb_); // The metadata store could be null if the login database initialization // fails. if (!password_store_sync_->GetMetadataStore()) { @@ -288,6 +290,8 @@ base::UmaHistogramCounts10000( "Sync.DownloadedPasswordsCountWhenInitialMergeFails", entity_data.size()); + } else { + sync_enabled_or_disabled_cb_.Run(); } return error; } @@ -770,6 +774,8 @@ } password_store_sync_->DeleteAndRecreateDatabaseFile(); password_store_sync_->NotifyLoginsChanged(password_store_changes); + + sync_enabled_or_disabled_cb_.Run(); } } }
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.h b/components/password_manager/core/browser/sync/password_sync_bridge.h index 5b4bdef8..e3c75ef 100644 --- a/components/password_manager/core/browser/sync/password_sync_bridge.h +++ b/components/password_manager/core/browser/sync/password_sync_bridge.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_PASSWORD_SYNC_BRIDGE_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_PASSWORD_SYNC_BRIDGE_H_ +#include "base/callback_forward.h" #include "base/macros.h" #include "base/sequence_checker.h" #include "components/password_manager/core/browser/password_store_change.h" @@ -33,7 +34,8 @@ // |password_store_sync| must not be null and must outlive this object. PasswordSyncBridge( std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, - PasswordStoreSync* password_store_sync); + PasswordStoreSync* password_store_sync, + const base::RepeatingClosure& sync_enabled_or_disabled_cb); ~PasswordSyncBridge() override; // Notifies the bridge of changes to the password database. Callers are @@ -76,6 +78,8 @@ // Password store responsible for persistence. PasswordStoreSync* const password_store_sync_; + base::RepeatingClosure sync_enabled_or_disabled_cb_; + // True if processing remote sync changes is in progress. Used to ignore // password store changes notifications while processing remote sync changes. bool is_processing_remote_sync_changes_ = false;
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc index 2aedcda1..ff93af0 100644 --- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc +++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" +#include "base/test/mock_callback.h" #include "components/password_manager/core/browser/password_store_sync.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/model/data_batch.h" @@ -233,8 +234,8 @@ .WillByDefault(Invoke(&fake_db_, &FakeDatabase::RemoveLogin)); bridge_ = std::make_unique<PasswordSyncBridge>( - mock_processor_.CreateForwardingProcessor(), - &mock_password_store_sync_); + mock_processor_.CreateForwardingProcessor(), &mock_password_store_sync_, + sync_enabled_or_disabled_cb_.Get()); // It's the responsibility of the PasswordStoreSync to inform the bridge // about changes in the password store. The bridge notifies the @@ -303,11 +304,16 @@ return &mock_password_store_sync_; } + base::MockRepeatingClosure* mock_sync_enabled_or_disabled_cb() { + return &sync_enabled_or_disabled_cb_; + } + private: FakeDatabase fake_db_; testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_; testing::NiceMock<MockSyncMetadataStore> mock_sync_metadata_store_sync_; testing::NiceMock<MockPasswordStoreSync> mock_password_store_sync_; + testing::NiceMock<base::MockRepeatingClosure> sync_enabled_or_disabled_cb_; std::unique_ptr<PasswordSyncBridge> bridge_; }; @@ -780,7 +786,7 @@ /*entities=*/testing::SizeIs(1)))); PasswordSyncBridge bridge(mock_processor().CreateForwardingProcessor(), - mock_password_store_sync()); + mock_password_store_sync(), base::DoNothing()); } // Tests that in case ReadAllLogins() during initial merge returns encryption @@ -807,4 +813,64 @@ bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList()); } +TEST_F(PasswordSyncBridgeTest, ShouldNotifyOnSyncEnable) { + ON_CALL(*mock_password_store_sync(), IsAccountStore()) + .WillByDefault(Return(true)); + + // New password data becoming available because sync was newly enabled should + // trigger the callback. + EXPECT_CALL(*mock_sync_enabled_or_disabled_cb(), Run()); + + syncer::EntityChangeList initial_entity_data; + initial_entity_data.push_back(syncer::EntityChange::CreateAdd( + /*storage_key=*/"", + SpecificsToEntity(CreateSpecificsWithSignonRealm(kSignonRealm1)))); + + base::Optional<syncer::ModelError> error = bridge()->MergeSyncData( + bridge()->CreateMetadataChangeList(), std::move(initial_entity_data)); + ASSERT_FALSE(error); +} + +TEST_F(PasswordSyncBridgeTest, ShouldNotNotifyOnSyncChange) { + ON_CALL(*mock_password_store_sync(), IsAccountStore()) + .WillByDefault(Return(true)); + + // New password data becoming available due to an incoming sync change should + // *not* trigger the callback. This is mainly for performance reasons: In + // practice, this callback will cause all PasswordFormManagers to re-query + // from the password store, which can be expensive. + EXPECT_CALL(*mock_sync_enabled_or_disabled_cb(), Run()).Times(0); + + syncer::EntityChangeList entity_changes; + entity_changes.push_back(syncer::EntityChange::CreateAdd( + /*storage_key=*/"", + SpecificsToEntity(CreateSpecificsWithSignonRealm(kSignonRealm1)))); + + base::Optional<syncer::ModelError> error = bridge()->ApplySyncChanges( + bridge()->CreateMetadataChangeList(), std::move(entity_changes)); + ASSERT_FALSE(error); +} + +TEST_F(PasswordSyncBridgeTest, ShouldNotifyOnSyncDisableIfAccountStore) { + ON_CALL(*mock_password_store_sync(), IsAccountStore()) + .WillByDefault(Return(true)); + + // The account password store gets cleared when sync is disabled, so this + // should trigger the callback. + EXPECT_CALL(*mock_sync_enabled_or_disabled_cb(), Run()); + + bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList()); +} + +TEST_F(PasswordSyncBridgeTest, ShouldNotNotifyOnSyncDisableIfProfileStore) { + ON_CALL(*mock_password_store_sync(), IsAccountStore()) + .WillByDefault(Return(false)); + + // The profile password store does *not* get cleared when sync is disabled, so + // this should *not* trigger the callback. + EXPECT_CALL(*mock_sync_enabled_or_disabled_cb(), Run()).Times(0); + + bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList()); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/sync/password_syncable_service.cc b/components/password_manager/core/browser/sync/password_syncable_service.cc index 331b0038..ae61ed5 100644 --- a/components/password_manager/core/browser/sync/password_syncable_service.cc +++ b/components/password_manager/core/browser/sync/password_syncable_service.cc
@@ -452,9 +452,7 @@ } bool PasswordSyncableService::ShouldRecoverPasswordsDuringMerge() const { - return base::FeatureList::IsEnabled( - features::kRecoverPasswordsForSyncUsers) && - !base::FeatureList::IsEnabled(features::kDeleteCorruptedPasswords); + return !base::FeatureList::IsEnabled(features::kDeleteCorruptedPasswords); } syncer::SyncData SyncDataFromPassword(
diff --git a/components/password_manager/core/browser/sync/password_syncable_service.h b/components/password_manager/core/browser/sync/password_syncable_service.h index 1173a3c..409838d 100644 --- a/components/password_manager/core/browser/sync/password_syncable_service.h +++ b/components/password_manager/core/browser/sync/password_syncable_service.h
@@ -88,14 +88,8 @@ // Returns true if corrupted passwords should be deleted from the local // database when merging data. - // There are two features that handle recovering lost passwords. - // RecoverPasswordsForSyncUsers recovers passwords for sync users when merging - // data with Sync. If that feature is disabled, this method returns false. - // Other feature, DeleteCorruptedPasswords, is introduced after the first - // feature and recovers both Sync and non-Sync users internally in - // LoginDatabase. When that feature is enabled, this method returns false. - // After launching DeleteCorruptedPasswords, RecoverPasswordsForSyncUsers - // and related code is to be cleaned up. + // This is true if the feature DeleteCorruptedPasswords is disabled, as it + // recovers both Sync and non-Sync users internally in LoginDatabase. bool ShouldRecoverPasswordsDuringMerge() const; // The factory that creates sync errors. |SyncError| has rich data
diff --git a/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc b/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc index 78d997b..f7fe2d2 100644 --- a/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc +++ b/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc
@@ -518,10 +518,8 @@ syncer::PASSWORDS); EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) .WillOnce(Return(false)); - if (base::FeatureList::IsEnabled(features::kRecoverPasswordsForSyncUsers)) { - EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()) - .WillOnce(Return(DatabaseCleanupResult::kDatabaseUnavailable)); - } + EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()) + .WillOnce(Return(DatabaseCleanupResult::kDatabaseUnavailable)); EXPECT_CALL(*error_factory, CreateAndUploadError(_, _)) .WillOnce(Return(error)); // ActOnPasswordStoreChanges() below shouldn't generate any changes for Sync. @@ -538,39 +536,23 @@ list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); service()->ActOnPasswordStoreChanges(list); } +class PasswordSyncableServiceTestWithoutDeleteCorruptedPasswords + : public PasswordSyncableServiceTest { + public: + PasswordSyncableServiceTestWithoutDeleteCorruptedPasswords() { + scoped_feature_list_.InitAndDisableFeature( + features::kDeleteCorruptedPasswords); + } -// Disable feature for deleting undecryptable logins. -TEST_F(PasswordSyncableServiceTest, RecoverPasswordsForSyncUsersDisabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - features::kRecoverPasswordsForSyncUsers); - auto error_factory = std::make_unique<syncer::SyncErrorFactoryMock>(); - syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, - "Failed to get passwords from store.", - syncer::PASSWORDS); - EXPECT_CALL(*error_factory, CreateAndUploadError(_, _)) - .WillOnce(Return(error)); + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(false)); - EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()).Times(0); - - syncer::SyncMergeResult result = service()->MergeDataAndStartSyncing( - syncer::PASSWORDS, SyncDataList(), std::move(processor_), - std::move(error_factory)); - EXPECT_TRUE(result.error().IsSet()); -} - -// Test that passwords are recovered for Sync users using the older feature -// (kRecoverPasswordsForSyncUsers) when feature for recovering passwords for -// Sync users is enabled, while feature for deleting corrupted passwords for -// all users is disabled. -TEST_F(PasswordSyncableServiceTest, RecoverPasswordsForSyncUsersEnabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {features::kRecoverPasswordsForSyncUsers}, - {features::kDeleteCorruptedPasswords}); - +// Test that passwords are recovered for Sync users using the older logic (i.e. +// recover passwords only for Sync users) when the feature for deleting +// corrupted passwords for all users is disabled. +TEST_F(PasswordSyncableServiceTestWithoutDeleteCorruptedPasswords, + RecoverPasswordsOnlyForSyncUsers) { EXPECT_CALL(*processor_, ProcessSyncChanges(_, IsEmpty())); EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) .Times(2) @@ -585,16 +567,22 @@ EXPECT_FALSE(result.error().IsSet()); } -// Test that passwords are not recovered using the older feature -// (kRecoverPasswordForSyncUsers) when merging data if both features for -// recovering passwords for Sync users and deleting passwords for all users -// are enabled. -TEST_F(PasswordSyncableServiceTest, PasswordRecoveryForAllUsersEnabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures({features::kRecoverPasswordsForSyncUsers, - features::kDeleteCorruptedPasswords}, - {}); +class PasswordSyncableServiceTestWithDeleteCorruptedPasswords + : public PasswordSyncableServiceTest { + public: + PasswordSyncableServiceTestWithDeleteCorruptedPasswords() { + scoped_feature_list_.InitAndEnableFeature( + features::kDeleteCorruptedPasswords); + } + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Test that passwords are not recovered when merging data if the feature for +// deleting passwords for all users is enabled. +TEST_F(PasswordSyncableServiceTestWithDeleteCorruptedPasswords, + PasswordRecoveryForAllUsersEnabled) { auto error_factory = std::make_unique<syncer::SyncErrorFactoryMock>(); syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "Failed to get passwords from store.", @@ -613,18 +601,8 @@ } // Database cleanup fails because encryption is unavailable. -// Flaky: crbug.com/1011193. -#if defined(OS_WIN) -#define MAYBE_FailedDeleteUndecryptableLogins \ - DISABLED_FailedDeleteUndecryptableLogins -#else -#define MAYBE_FailedDeleteUndecryptableLogins FailedDeleteUndecryptableLogins -#endif -TEST_F(PasswordSyncableServiceTest, MAYBE_FailedDeleteUndecryptableLogins) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {features::kRecoverPasswordsForSyncUsers}, - {features::kDeleteCorruptedPasswords}); +TEST_F(PasswordSyncableServiceTestWithoutDeleteCorruptedPasswords, + FailedDeleteUndecryptableLogins) { auto error_factory = std::make_unique<syncer::SyncErrorFactoryMock>(); syncer::SyncError error( FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index 242a0db..2230d73 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -75,11 +75,6 @@ const base::Feature kPasswordSaveIllustration = { "SavePasswordIllustration", base::FEATURE_DISABLED_BY_DEFAULT}; -// Deletes entries from local database on Mac which cannot be decrypted when -// merging data with Sync. -const base::Feature kRecoverPasswordsForSyncUsers = { - "RecoverPasswordsForSyncUsers", base::FEATURE_ENABLED_BY_DEFAULT}; - // Enables support of filling and saving on username first flow. const base::Feature kUsernameFirstFlow = {"UsernameFirstFlow", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h index fb76fce..41ce08a 100644 --- a/components/password_manager/core/common/password_manager_features.h +++ b/components/password_manager/core/common/password_manager_features.h
@@ -31,7 +31,6 @@ extern const base::Feature kPasswordImport; extern const base::Feature kPasswordManagerOnboardingAndroid; extern const base::Feature kPasswordSaveIllustration; -extern const base::Feature kRecoverPasswordsForSyncUsers; extern const base::Feature kUsernameFirstFlow; extern const base::Feature kStickyBubble;
diff --git a/components/sync/OWNERS b/components/sync/OWNERS index e90fa107..2381d48 100644 --- a/components/sync/OWNERS +++ b/components/sync/OWNERS
@@ -1,5 +1,4 @@ jkrcal@chromium.org -mamir@chromium.org mastiz@chromium.org melandory@chromium.org treib@chromium.org
diff --git a/components/sync/engine_impl/loopback_server/loopback_server.cc b/components/sync/engine_impl/loopback_server/loopback_server.cc index 8c15595..a2135dd 100644 --- a/components/sync/engine_impl/loopback_server/loopback_server.cc +++ b/components/sync/engine_impl/loopback_server/loopback_server.cc
@@ -15,6 +15,7 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" +#include "base/sequence_checker.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -255,7 +256,7 @@ bool LoopbackServer::CreatePermanentBookmarkFolder( const std::string& server_tag, const std::string& name) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<LoopbackServerEntity> entity = PersistentPermanentEntity::CreateNew( syncer::BOOKMARKS, server_tag, name, @@ -306,7 +307,7 @@ net::HttpStatusCode LoopbackServer::HandleCommand(const string& request, std::string* response) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); response->clear(); sync_pb::ClientToServerMessage message; @@ -663,7 +664,7 @@ } void LoopbackServer::ClearServerData() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); entities_.clear(); keystore_keys_.clear(); ++store_birthday_; @@ -672,13 +673,13 @@ } std::string LoopbackServer::GetStoreBirthday() const { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return base::NumberToString(store_birthday_); } std::vector<sync_pb::SyncEntity> LoopbackServer::GetSyncEntitiesByModelType( ModelType model_type) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::vector<sync_pb::SyncEntity> sync_entities; for (const auto& kv : entities_) { const LoopbackServerEntity& entity = *kv.second; @@ -694,7 +695,7 @@ std::vector<sync_pb::SyncEntity> LoopbackServer::GetPermanentSyncEntitiesByModelType(ModelType model_type) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::vector<sync_pb::SyncEntity> sync_entities; for (const auto& kv : entities_) { const LoopbackServerEntity& entity = *kv.second; @@ -710,7 +711,7 @@ std::unique_ptr<base::DictionaryValue> LoopbackServer::GetEntitiesAsDictionaryValue() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<base::DictionaryValue> dictionary( new base::DictionaryValue()); @@ -783,7 +784,7 @@ } void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); proto->set_version(kCurrentLoopbackServerProtoVersion); proto->set_store_birthday(store_birthday_); @@ -798,7 +799,7 @@ bool LoopbackServer::DeSerializeState( const sync_pb::LoopbackServerProto& proto) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(proto.version(), kCurrentLoopbackServerProtoVersion); store_birthday_ = proto.store_birthday();
diff --git a/components/sync/engine_impl/loopback_server/loopback_server.h b/components/sync/engine_impl/loopback_server/loopback_server.h index 85f98e1..a0807c6 100644 --- a/components/sync/engine_impl/loopback_server/loopback_server.h +++ b/components/sync/engine_impl/loopback_server/loopback_server.h
@@ -15,7 +15,7 @@ #include "base/callback.h" #include "base/files/file_path.h" #include "base/optional.h" -#include "base/threading/thread_checker.h" +#include "base/sequence_checker.h" #include "base/values.h" #include "components/sync/base/model_type.h" #include "components/sync/engine_impl/loopback_server/loopback_server_entity.h" @@ -235,8 +235,8 @@ // The file used to store the local sync data. base::FilePath persistent_file_; - // Used to verify that LoopbackServer is only used from one thread. - base::ThreadChecker thread_checker_; + // Used to verify that LoopbackServer is only used from one sequence. + SEQUENCE_CHECKER(sequence_checker_); // Used to observe the completion of commit messages for the sake of testing. ObserverForTests* observer_for_tests_;
diff --git a/components/sync/nigori/cryptographer_impl.cc b/components/sync/nigori/cryptographer_impl.cc index ac38cd4..0894b38 100644 --- a/components/sync/nigori/cryptographer_impl.cc +++ b/components/sync/nigori/cryptographer_impl.cc
@@ -97,6 +97,10 @@ new CryptographerImpl(key_bag_.Clone(), default_encryption_key_name_)); } +size_t CryptographerImpl::KeyBagSizeForTesting() const { + return key_bag_.size(); +} + std::unique_ptr<Cryptographer> CryptographerImpl::Clone() const { return CloneImpl(); }
diff --git a/components/sync/nigori/cryptographer_impl.h b/components/sync/nigori/cryptographer_impl.h index 2afc6e0..3fb58d7 100644 --- a/components/sync/nigori/cryptographer_impl.h +++ b/components/sync/nigori/cryptographer_impl.h
@@ -75,6 +75,8 @@ // Similar to Clone() but returns CryptographerImpl. std::unique_ptr<CryptographerImpl> CloneImpl() const; + size_t KeyBagSizeForTesting() const; + // Cryptographer overrides. std::unique_ptr<Cryptographer> Clone() const override; bool CanEncrypt() const override;
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc index f04a3ce..8722caf 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -494,15 +494,18 @@ return; } - const std::string new_key_name = state_.cryptographer->EmplaceKey( - passphrase, GetKeyDerivationParamsForPendingKeys()); - if (new_key_name.empty()) { - processor_->ReportError(ModelError( - FROM_HERE, "Failed to add decryption passphrase to cryptographer.")); + NigoriKeyBag tmp_key_bag = NigoriKeyBag::CreateEmpty(); + const std::string new_key_name = + tmp_key_bag.AddKey(Nigori::CreateByDerivation( + GetKeyDerivationParamsForPendingKeys(), passphrase)); + + base::Optional<ModelError> error = TryDecryptPendingKeysWith(tmp_key_bag); + if (error.has_value()) { + processor_->ReportError(*error); return; } - if (!TryDecryptPendingKeys()) { + if (state_.pending_keys.has_value()) { // |pending_keys| could be changed in between of OnPassphraseRequired() // and SetDecryptionPassphrase() calls (remote update with different // keystore Nigori or with transition from keystore to custom passphrase @@ -511,17 +514,11 @@ return; } - state_.cryptographer->SelectDefaultEncryptionKey(new_key_name); - + DCHECK_EQ(state_.cryptographer->GetDefaultEncryptionKeyName(), new_key_name); storage_->StoreData(SerializeAsNigoriLocalData()); broadcasting_observer_->OnCryptographerStateChanged( state_.cryptographer.get(), state_.pending_keys.has_value()); broadcasting_observer_->OnPassphraseAccepted(); - - // TODO(crbug.com/922900): we may need to rewrite encryption_keybag in Nigori - // node in case we have some keys in |cryptographer_| which is not stored in - // encryption_keybag yet. - NOTIMPLEMENTED(); } void NigoriSyncBridgeImpl::AddTrustedVaultDecryptionKeys( @@ -534,28 +531,28 @@ return; } + NigoriKeyBag tmp_key_bag = NigoriKeyBag::CreateEmpty(); for (const std::string& key : keys) { if (!key.empty()) { - state_.cryptographer->EmplaceKey(key, - GetKeyDerivationParamsForPendingKeys()); + tmp_key_bag.AddKey(Nigori::CreateByDerivation( + GetKeyDerivationParamsForPendingKeys(), key)); } } - const std::string pending_key_name = state_.pending_keys->key_name(); + base::Optional<ModelError> error = TryDecryptPendingKeysWith(tmp_key_bag); + if (error.has_value()) { + processor_->ReportError(*error); + return; + } - if (TryDecryptPendingKeys()) { - state_.cryptographer->SelectDefaultEncryptionKey(pending_key_name); + if (state_.pending_keys.has_value()) { + return; } storage_->StoreData(SerializeAsNigoriLocalData()); - broadcasting_observer_->OnCryptographerStateChanged( state_.cryptographer.get(), state_.pending_keys.has_value()); - - if (!state_.pending_keys) { - broadcasting_observer_->OnTrustedVaultKeyAccepted(); - } - + broadcasting_observer_->OnTrustedVaultKeyAccepted(); MaybeNotifyBootstrapTokenUpdated(); } @@ -813,6 +810,8 @@ DCHECK(!encryption_keybag.blob().empty()); DCHECK(!keystore_decryptor_token.blob().empty()); + const bool had_pending_keys_before_update = state_.pending_keys.has_value(); + // Decryption of |keystore_decryptor_token|. NigoriKeyBag keystore_decryptor_key_bag = NigoriKeyBag::CreateEmpty(); sync_pb::NigoriKey keystore_decryptor_key; @@ -824,29 +823,27 @@ state_.pending_keystore_decryptor_token = keystore_decryptor_token; } - // TODO(crbug.com/922900): issue ModelError if |keystore_decryptor_keybag| is - // not empty and can't decrypt the |encryption_keybag|? - if (keystore_decryptor_key_bag.CanDecrypt(encryption_keybag)) { - // |encryption_keybag| must contain the key it was encrypted with, so it's - // okay to add it earlier. - state_.cryptographer->EmplaceKeysFrom(keystore_decryptor_key_bag); + // In order to decrypt |encryption_keybag|, temporarily set pending keys + // before calling TryDecryptPendingKeysWith(). + state_.pending_keys = encryption_keybag; + state_.cryptographer->ClearDefaultEncryptionKey(); + + base::Optional<ModelError> error = + TryDecryptPendingKeysWith(keystore_decryptor_key_bag); + if (error.has_value()) { + return error; } - // Decryption of |encryption_keybag|. - sync_pb::NigoriKeyBag key_bag; - if (!state_.cryptographer->Decrypt(encryption_keybag, &key_bag)) { - state_.cryptographer->ClearDefaultEncryptionKey(); - state_.pending_keys = encryption_keybag; + if (state_.pending_keys.has_value()) { + // TODO(crbug.com/922900): issue ModelError if + // |keystore_decryptor_keybag| is not empty? return base::nullopt; } - state_.cryptographer->EmplaceKeysFrom(NigoriKeyBag::CreateFromProto(key_bag)); - state_.cryptographer->SelectDefaultEncryptionKey( - encryption_keybag.key_name()); - if (state_.pending_keys) { - state_.pending_keys.reset(); + if (had_pending_keys_before_update) { broadcasting_observer_->OnPassphraseAccepted(); } + return base::nullopt; } @@ -892,16 +889,38 @@ state_.cryptographer->EmplaceKeysFrom(NigoriKeyBag::CreateFromProto(key_bag)); } -bool NigoriSyncBridgeImpl::TryDecryptPendingKeys() { - sync_pb::NigoriKeyBag decrypted_pending_keys; - if (!state_.cryptographer->Decrypt(*state_.pending_keys, - &decrypted_pending_keys)) { - return false; +base::Optional<ModelError> NigoriSyncBridgeImpl::TryDecryptPendingKeysWith( + const NigoriKeyBag& key_bag) { + DCHECK(state_.pending_keys.has_value()); + DCHECK(state_.cryptographer->GetDefaultEncryptionKeyName().empty()); + + std::string decrypted_pending_keys_str; + if (!key_bag.Decrypt(*state_.pending_keys, &decrypted_pending_keys_str)) { + return base::nullopt; } - state_.cryptographer->EmplaceKeysFrom( - NigoriKeyBag::CreateFromProto(decrypted_pending_keys)); + + sync_pb::NigoriKeyBag decrypted_pending_keys; + if (!decrypted_pending_keys.ParseFromString(decrypted_pending_keys_str)) { + return base::nullopt; + } + + const std::string new_default_key_name = state_.pending_keys->key_name(); + DCHECK(key_bag.HasKey(new_default_key_name)); + + NigoriKeyBag new_key_bag = + NigoriKeyBag::CreateFromProto(decrypted_pending_keys); + + if (!new_key_bag.HasKey(new_default_key_name)) { + // Protocol violation. + return ModelError(FROM_HERE, + "Received keybag is missing the new default key."); + } + + state_.cryptographer->EmplaceKeysFrom(new_key_bag); + state_.cryptographer->SelectDefaultEncryptionKey(new_default_key_name); state_.pending_keys.reset(); - return true; + + return base::nullopt; } std::unique_ptr<EntityData> NigoriSyncBridgeImpl::GetData() { @@ -962,7 +981,8 @@ broadcasting_observer_->OnEncryptedTypesChanged(SensitiveTypes(), false); } -const Cryptographer& NigoriSyncBridgeImpl::GetCryptographerForTesting() const { +const CryptographerImpl& NigoriSyncBridgeImpl::GetCryptographerForTesting() + const { return *state_.cryptographer; }
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h index fe9dd43..97c583ac 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.h +++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -85,7 +85,7 @@ // TODO(crbug.com/922900): investigate whether we need this getter outside of // tests and decide whether this method should be a part of // SyncEncryptionHandler interface. - const Cryptographer& GetCryptographerForTesting() const; + const CryptographerImpl& GetCryptographerForTesting() const; sync_pb::NigoriSpecifics::PassphraseType GetPassphraseTypeForTesting() const; ModelTypeSet GetEncryptedTypesForTesting() const; bool HasPendingKeysForTesting() const; @@ -105,11 +105,20 @@ void UpdateCryptographerFromNonKeystoreNigori( const sync_pb::EncryptedData& keybag); - // Uses the cryptographer to try to decrypt pending keys. If success, the - // newly decrypted keys are put in the cryptographer's keybag, pending keys - // are cleared and the function returns true. Otherwise, it returns false and - // the state remains unchanged. It does not change the default key. - bool TryDecryptPendingKeys(); + // Uses |key_bag| to try to decrypt pending keys as represented in + // |state_.pending_keys| (which must be set). + // + // If decryption is possible, the newly decrypted keys are put in the + // |state_.cryptographer|'s keybag and the default key is updated. In that + // case pending keys are cleared. + // + // If |key_bag| is not capable of decrypting pending keys, + // |state_.pending_keys| stays set. Such outcome is not itself considered + // and error and returns base::nullopt. + // + // Errors may be returned, in rare cases, for fatal protocol violations. + base::Optional<ModelError> TryDecryptPendingKeysWith( + const NigoriKeyBag& key_bag); base::Time GetExplicitPassphraseTime() const;
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc index 06b0cb2..17de4ad 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -730,6 +730,7 @@ TEST_F(NigoriSyncBridgeImplTest, ShouldNotifyWhenDecryptionWithPassphraseFailed) { const KeyParams kKeystoreKeyParams = KeystoreKeyParams("keystore_key"); + EntityData entity_data; *entity_data.specifics.mutable_nigori() = BuildKeystoreNigoriSpecifics( /*keybag_keys_params=*/{kKeystoreKeyParams}, @@ -749,6 +750,10 @@ /*pending_keys=*/ EncryptedDataEq(expected_pending_keys))); bridge()->SetDecryptionPassphrase("wrong_passphrase"); + + const CryptographerImpl& cryptographer = + bridge()->GetCryptographerForTesting(); + EXPECT_THAT(cryptographer.KeyBagSizeForTesting(), Eq(size_t(0))); } // Tests that attempt to SetEncryptionPassphrase() has no effect (at least @@ -1324,6 +1329,36 @@ EXPECT_THAT(bridge()->GetData(), HasCustomPassphraseNigori()); } +TEST_F(NigoriSyncBridgeImplTest, + ShouldNotAddDecryptionKeysToTrustedVaultCryptographer) { + const std::string kTrustedVaultKey1 = "trusted_vault_key_1"; + const std::string kTrustedVaultKey2 = "trusted_vault_key_2"; + EntityData entity_data; + *entity_data.specifics.mutable_nigori() = + BuildTrustedVaultNigoriSpecifics({Pbkdf2KeyParams(kTrustedVaultKey1)}); + + ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"})); + EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)), + Eq(base::nullopt)); + EXPECT_TRUE(bridge()->Init()); + ASSERT_THAT(bridge()->GetPassphraseTypeForTesting(), + Eq(sync_pb::NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE)); + ASSERT_TRUE(bridge()->HasPendingKeysForTesting()); + + // Note that |kTrustedVaultKey2| was not part of Nigori specifics. + bridge()->AddTrustedVaultDecryptionKeys( + {kTrustedVaultKey1, kTrustedVaultKey2}); + ASSERT_FALSE(bridge()->HasPendingKeysForTesting()); + + const CryptographerImpl& cryptographer = + bridge()->GetCryptographerForTesting(); + ASSERT_THAT(cryptographer, + CanDecryptWith(Pbkdf2KeyParams(kTrustedVaultKey1))); + EXPECT_THAT(cryptographer, + Not(CanDecryptWith(Pbkdf2KeyParams(kTrustedVaultKey2)))); + EXPECT_THAT(cryptographer.KeyBagSizeForTesting(), Eq(size_t(1))); +} + } // namespace } // namespace syncer
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc index f1675576..5acee27 100644 --- a/components/sync_bookmarks/synced_bookmark_tracker.cc +++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -209,6 +209,12 @@ return it != sync_id_to_entities_map_.end() ? it->second.get() : nullptr; } +SyncedBookmarkTracker::Entity* SyncedBookmarkTracker::GetMutableEntityForSyncId( + const std::string& sync_id) { + auto it = sync_id_to_entities_map_.find(sync_id); + return it != sync_id_to_entities_map_.end() ? it->second.get() : nullptr; +} + const SyncedBookmarkTracker::Entity* SyncedBookmarkTracker::GetEntityForBookmarkNode( const bookmarks::BookmarkNode* node) const { @@ -248,9 +254,7 @@ const sync_pb::UniquePosition& unique_position, const sync_pb::EntitySpecifics& specifics) { DCHECK_GT(specifics.ByteSize(), 0); - auto it = sync_id_to_entities_map_.find(sync_id); - DCHECK(it != sync_id_to_entities_map_.end()); - Entity* entity = it->second.get(); + Entity* entity = GetMutableEntityForSyncId(sync_id); DCHECK(entity); DCHECK_EQ(entity->metadata()->server_id(), sync_id); entity->metadata()->set_server_version(server_version); @@ -264,25 +268,20 @@ void SyncedBookmarkTracker::UpdateServerVersion(const std::string& sync_id, int64_t server_version) { - auto it = sync_id_to_entities_map_.find(sync_id); - DCHECK(it != sync_id_to_entities_map_.end()); - Entity* entity = it->second.get(); + Entity* entity = GetMutableEntityForSyncId(sync_id); DCHECK(entity); entity->metadata()->set_server_version(server_version); } void SyncedBookmarkTracker::MarkCommitMayHaveStarted( const std::string& sync_id) { - auto it = sync_id_to_entities_map_.find(sync_id); - DCHECK(it != sync_id_to_entities_map_.end()); - Entity* entity = it->second.get(); + Entity* entity = GetMutableEntityForSyncId(sync_id); DCHECK(entity); entity->set_commit_may_have_started(true); } void SyncedBookmarkTracker::MarkDeleted(const std::string& sync_id) { - auto it = sync_id_to_entities_map_.find(sync_id); - Entity* entity = it->second.get(); + Entity* entity = GetMutableEntityForSyncId(sync_id); DCHECK(entity); entity->metadata()->set_is_deleted(true); // Clear all references to the deleted bookmark node. @@ -308,7 +307,7 @@ // TODO(crbug.com/516866): The below CHECK is added to debug some crashes. // Should be switched to a DCHECK after figuring out the reason for the crash. CHECK_NE(0U, sync_id_to_entities_map_.count(sync_id)); - Entity* entity = sync_id_to_entities_map_.find(sync_id)->second.get(); + Entity* entity = GetMutableEntityForSyncId(sync_id); DCHECK(entity); // TODO(crbug.com/516866): Update base hash specifics here if the entity is // not already out of sync. @@ -472,9 +471,7 @@ int64_t acked_sequence_number, int64_t server_version) { // TODO(crbug.com/516866): Update specifics if we decide to keep it. - auto it = sync_id_to_entities_map_.find(old_id); - Entity* entity = - it != sync_id_to_entities_map_.end() ? it->second.get() : nullptr; + Entity* entity = GetMutableEntityForSyncId(old_id); if (!entity) { DLOG(WARNING) << "Trying to update a non existing entity."; return; @@ -516,15 +513,13 @@ return; } bookmark_node_to_entities_map_[new_node] = - std::move(bookmark_node_to_entities_map_[old_node]); + bookmark_node_to_entities_map_[old_node]; bookmark_node_to_entities_map_[new_node]->set_bookmark_node(new_node); bookmark_node_to_entities_map_.erase(old_node); } void SyncedBookmarkTracker::AckSequenceNumber(const std::string& sync_id) { - auto it = sync_id_to_entities_map_.find(sync_id); - Entity* entity = - it != sync_id_to_entities_map_.end() ? it->second.get() : nullptr; + Entity* entity = GetMutableEntityForSyncId(sync_id); DCHECK(entity); entity->metadata()->set_acked_sequence_number( entity->metadata()->sequence_number());
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h index 487342d..9be8db4 100644 --- a/components/sync_bookmarks/synced_bookmark_tracker.h +++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -31,10 +31,10 @@ using NodeMetadataPair = std::pair<const bookmarks::BookmarkNode*, std::unique_ptr<sync_pb::EntityMetadata>>; -// This class is responsible for keeping the mapping between bookmarks node in +// This class is responsible for keeping the mapping between bookmark nodes in // the local model and the server-side corresponding sync entities. It manages -// the metadata for its entity and caches entity data upon a local change until -// commit confirmation is received. +// the metadata for its entities and caches entity data upon a local change +// until commit confirmation is received. class SyncedBookmarkTracker { public: class Entity { @@ -55,7 +55,7 @@ // Check whether |specifics| matches the stored specifics_hash. bool MatchesSpecificsHash(const sync_pb::EntitySpecifics& specifics) const; - // Returns null for tomstones. + // Returns null for tombstones. const bookmarks::BookmarkNode* bookmark_node() const { return bookmark_node_; } @@ -163,7 +163,7 @@ void Remove(const std::string& sync_id); // Increment sequence number in the metadata for the entity with |sync_id|. - // Tracker must contain a non-tomstone entity with server id = |sync_id|. + // Tracker must contain a non-tombstone entity with server id = |sync_id|. void IncrementSequenceNumber(const std::string& sync_id); sync_pb::BookmarkModelMetadata BuildBookmarkModelMetadata() const; @@ -232,6 +232,9 @@ const bookmarks::BookmarkModel* bookmark_model) const; private: + // Returns null if no entity is found. + Entity* GetMutableEntityForSyncId(const std::string& sync_id); + // Reorders |entities| that represents local non-deletions such that parent // creation/update is before child creation/update. Returns the ordered list. std::vector<const Entity*> ReorderUnsyncedEntitiesExceptDeletions(
diff --git a/components/sync_preferences/BUILD.gn b/components/sync_preferences/BUILD.gn index ed1dbe4..5ef9a0c 100644 --- a/components/sync_preferences/BUILD.gn +++ b/components/sync_preferences/BUILD.gn
@@ -14,8 +14,6 @@ "pref_service_syncable_factory.cc", "pref_service_syncable_factory.h", "pref_service_syncable_observer.h", - "synced_pref_change_registrar.cc", - "synced_pref_change_registrar.h", "synced_pref_observer.h", ]
diff --git a/components/sync_preferences/synced_pref_change_registrar.cc b/components/sync_preferences/synced_pref_change_registrar.cc deleted file mode 100644 index a900600..0000000 --- a/components/sync_preferences/synced_pref_change_registrar.cc +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2013 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/sync_preferences/synced_pref_change_registrar.h" - -#include "base/bind.h" - -namespace sync_preferences { - -namespace { - -void InvokeUnnamedCallback( - const SyncedPrefChangeRegistrar::ChangeCallback& callback, - const std::string& path, - bool from_sync) { - callback.Run(from_sync); -} - -} // namespace - -SyncedPrefChangeRegistrar::SyncedPrefChangeRegistrar( - PrefServiceSyncable* pref_service) { - pref_service_ = pref_service; -} - -SyncedPrefChangeRegistrar::~SyncedPrefChangeRegistrar() { - RemoveAll(); -} - -void SyncedPrefChangeRegistrar::Add(const char* path, - const ChangeCallback& callback) { - Add(path, base::Bind(InvokeUnnamedCallback, callback)); -} - -void SyncedPrefChangeRegistrar::Add(const char* path, - const NamedChangeCallback& callback) { - DCHECK(!IsObserved(path)); - observers_[path] = callback; - pref_service_->AddSyncedPrefObserver(path, this); -} - -void SyncedPrefChangeRegistrar::Remove(const char* path) { - observers_.erase(path); - pref_service_->RemoveSyncedPrefObserver(path, this); -} - -void SyncedPrefChangeRegistrar::RemoveAll() { - for (auto iter = observers_.begin(); iter != observers_.end(); ++iter) { - pref_service_->RemoveSyncedPrefObserver(iter->first, this); - } - observers_.clear(); -} - -bool SyncedPrefChangeRegistrar::IsObserved(const char* path) const { - return observers_.find(path) != observers_.end(); -} - -void SyncedPrefChangeRegistrar::OnSyncedPrefChanged(const std::string& path, - bool from_sync) { - if (pref_service_->IsManagedPreference(path)) - return; - ObserverMap::const_iterator iter = observers_.find(path); - if (iter == observers_.end()) - return; - iter->second.Run(path, from_sync); -} - -} // namespace sync_preferences
diff --git a/components/sync_preferences/synced_pref_change_registrar.h b/components/sync_preferences/synced_pref_change_registrar.h deleted file mode 100644 index 23b62cc..0000000 --- a/components/sync_preferences/synced_pref_change_registrar.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2013 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_SYNC_PREFERENCES_SYNCED_PREF_CHANGE_REGISTRAR_H_ -#define COMPONENTS_SYNC_PREFERENCES_SYNCED_PREF_CHANGE_REGISTRAR_H_ - -#include <map> -#include <string> - -#include "base/callback.h" -#include "base/macros.h" -#include "components/sync_preferences/pref_service_syncable.h" -#include "components/sync_preferences/synced_pref_observer.h" - -namespace sync_preferences { - -// Manages the registration of one or more SyncedPrefObservers on a -// PrefServiceSyncable. This is modeled after base::PrefChangeRegistrar, and -// it should be used whenever it's necessary to determine whether a pref change -// has come from sync or from some other mechanism (managed, UI, external, etc.) -class SyncedPrefChangeRegistrar : public SyncedPrefObserver { - public: - // Registered callbacks may optionally take a path argument. - // The boolean argument indicates whether (true) or not (false) - // the change was a result of syncing. - typedef base::Callback<void(bool)> ChangeCallback; - typedef base::Callback<void(const std::string&, bool)> NamedChangeCallback; - - explicit SyncedPrefChangeRegistrar(PrefServiceSyncable* pref_service); - virtual ~SyncedPrefChangeRegistrar(); - - // Register an observer callback for sync change events on the pref at - // |path|. Only one callback may be registered per pref. - void Add(const char* path, const ChangeCallback& callback); - void Add(const char* path, const NamedChangeCallback& callback); - - // Remove the registered observer for |path|. - void Remove(const char* path); - - // Remove all registered observers. - void RemoveAll(); - - // Indicates whether or not an observer is already registered for |path|. - bool IsObserved(const char* path) const; - - private: - // SyncedPrefObserver implementation - void OnSyncedPrefChanged(const std::string& path, bool from_sync) override; - - typedef std::map<std::string, NamedChangeCallback> ObserverMap; - - PrefServiceSyncable* pref_service_; - ObserverMap observers_; - - DISALLOW_COPY_AND_ASSIGN(SyncedPrefChangeRegistrar); -}; - -} // namespace sync_preferences - -#endif // COMPONENTS_SYNC_PREFERENCES_SYNCED_PREF_CHANGE_REGISTRAR_H_
diff --git a/components/test/data/autofill_assistant/html_iframe/autofill_assistant_external_iframe.html b/components/test/data/autofill_assistant/html_iframe/autofill_assistant_external_iframe.html index 7304a41..f5cc996 100644 --- a/components/test/data/autofill_assistant/html_iframe/autofill_assistant_external_iframe.html +++ b/components/test/data/autofill_assistant/html_iframe/autofill_assistant_external_iframe.html
@@ -13,15 +13,29 @@ <script> var removeDiv = function() { - var div = document.getElementById("div"); + var div = document.getElementById("divToRemove"); div.parentNode.removeChild(div); } + + var setText = function() { + var select = document.getElementById("select"); + var input = document.getElementById("myPet"); + input.value = select.options[select.selectedIndex].label; + } </script> </head> <body> <button id="button" type="button" onclick="removeDiv()">Button</button> - <div id="div">Text</div> + <div id="divToRemove">Text</div> <input id="input" type="text" /> + + <select id="select" name="pet" onchange="setText()"> + <option value="Dog">Dog</option> + <option value="Cat">Cat</option> + <option value="Hamster">Hamster</option> + <option value="Fish">Fish</option> + </select> + <input type="text" id="myPet"/> </body> </html>
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index 2e4f209e..2fe8a97 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -110,6 +110,26 @@ << location.ToString(); } + void ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason reason, + base::Location location) { + base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason); + AddSampleToBuckets(&expected_not_restored_, sample); + + EXPECT_EQ(expected_not_restored_, + histogram_tester_.GetAllSamples( + "BackForwardCache.HistoryNavigationOutcome." + "NotRestoredReason")) + << location.ToString(); + } + + void ExpectNotRestoredIsEmpty(base::Location location) { + EXPECT_THAT(histogram_tester_.GetAllSamples( + "BackForwardCache.HistoryNavigationOutcome." + "NotRestoredReason"), + ElementsAre()) + << location.ToString(); + } + void ExpectDisabledWithReason(const std::string& reason, base::Location location) { base::HistogramBase::Sample sample = @@ -123,24 +143,6 @@ << location.ToString(); } - void ExpectEvicted(BackForwardCacheMetrics::EvictedReason reason, - base::Location location) { - base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason); - AddSampleToBuckets(&expected_eviction_reasons_, sample); - - EXPECT_EQ(expected_eviction_reasons_, - histogram_tester_.GetAllSamples( - "BackForwardCache.HistoryNavigationOutcome.EvictedReason")) - << location.ToString(); - } - - void ExpectEvictedIsEmpty(base::Location location) { - EXPECT_THAT(histogram_tester_.GetAllSamples( - "BackForwardCache.HistoryNavigationOutcome.EvictedReason"), - ElementsAre()) - << location.ToString(); - } - void ExpectEvictedAfterCommitted( std::vector<BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason> reasons, @@ -175,8 +177,8 @@ FrameTreeVisualizer visualizer_; base::HistogramTester histogram_tester_; std::vector<base::Bucket> expected_outcomes_; + std::vector<base::Bucket> expected_not_restored_; std::vector<base::Bucket> expected_disabled_reasons_; - std::vector<base::Bucket> expected_eviction_reasons_; std::vector<base::Bucket> expected_eviction_after_committing_; }; @@ -369,6 +371,30 @@ FROM_HERE); } +// The BackForwardCache does not cache same-website navigations for now. +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, + DoesNotCacheSameWebsiteNavigations) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html")); + + // 1) Navigate to A1. + EXPECT_TRUE(NavigateToURL(shell(), url_a1)); + RenderFrameHostImpl* rfh_a1 = current_frame_host(); + RenderFrameDeletedObserver delete_rfh_a1(rfh_a1); + int browsing_instance_id = rfh_a1->GetSiteInstance()->GetBrowsingInstanceId(); + + // 2) Navigate to A2. + EXPECT_TRUE(NavigateToURL(shell(), url_a2)); + RenderFrameHostImpl* rfh_a2 = current_frame_host(); + // The BrowsingInstance shouldn't have changed. + EXPECT_EQ(browsing_instance_id, + rfh_a2->GetSiteInstance()->GetBrowsingInstanceId()); + EXPECT_FALSE(rfh_a1->is_in_back_forward_cache()); + // The main frame should have been reused for the navigation. + EXPECT_EQ(rfh_a1, rfh_a2); +} + // The current page can't enter the BackForwardCache if another page can script // it. This can happen when one document opens a popup using window.open() for // instance. It prevents the BackForwardCache from being used. @@ -491,7 +517,7 @@ // 3) Flush A. web_contents()->GetController().GetBackForwardCache().Flush(); - EXPECT_TRUE(delete_observer_rfh_a.deleted()); // Flush is synchronous. + delete_observer_rfh_a.WaitUntilDeleted(); EXPECT_FALSE(delete_observer_rfh_b.deleted()); // 4) Go back to a new A. @@ -501,7 +527,7 @@ // 5) Flush B. web_contents()->GetController().GetBackForwardCache().Flush(); - EXPECT_TRUE(delete_observer_rfh_b.deleted()); // Flush is synchronous. + delete_observer_rfh_b.WaitUntilDeleted(); } // Check the visible URL in the omnibox is properly updated when restoring a @@ -558,7 +584,8 @@ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, FROM_HERE); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kCacheLimit, FROM_HERE); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason::kCacheLimit, + FROM_HERE); } // Test documents are evicted from the BackForwardCache at some point. @@ -1079,6 +1106,13 @@ // The page with the unsupported feature should be deleted (not cached). delete_observer_rfh_a.WaitUntilDeleted(); + + // Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1098,6 +1132,13 @@ // The page with the unsupported feature should be deleted (not cached). delete_rfh_a.WaitUntilDeleted(); + + // Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1198,6 +1239,13 @@ // The page was still recording audio when we navigated away, so it shouldn't // have been cached. deleted.WaitUntilDeleted(); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1226,6 +1274,13 @@ // The page was still recording audio when we navigated away, so it shouldn't // have been cached. deleted.WaitUntilDeleted(); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1261,6 +1316,12 @@ // The page was still loading when we navigated away, so it shouldn't have // been cached. delete_observer_rfh_a.WaitUntilDeleted(); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_FALSE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason::kLoading, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1283,6 +1344,15 @@ // The page was still loading when we navigated away, so it shouldn't have // been cached. delete_observer_rfh_a.WaitUntilDeleted(); + + // 3) Go back. + TestNavigationManager navigation_manager_back(shell()->web_contents(), url); + web_contents()->GetController().GoBack(); + navigation_manager_back.WaitForNavigationFinished(); + // The recorded reason is 'blocklisted features: outstanding network request'. + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1314,6 +1384,12 @@ // The page should not have been added to cache, since it had a subframe that // was still loading at the time it was navigated away from. delete_observer_rfh_a.WaitUntilDeleted(); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason::kLoading, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1346,6 +1422,12 @@ // The page should not have been added to the cache, since it had an iframe // that was still loading at the time it was navigated away from. delete_rfh_a.WaitUntilDeleted(); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason::kLoading, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfWebGL) { @@ -1360,9 +1442,17 @@ // 2) Navigate away. shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html")); + delete_observer_rfh_a.WaitUntilDeleted(); // The page had an active WebGL context when we navigated away, // so it shouldn't have been cached. + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfHttpError) { @@ -1381,6 +1471,12 @@ // The page did not return 200 (OK), so it shouldn't have been cached. delete_rfh_a.WaitUntilDeleted(); + + // Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK, FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1415,6 +1511,12 @@ // The page had a networking error, so it shouldn't have been cached. delete_rfh_a.WaitUntilDeleted(); + + // Go back. + web_contents()->GetController().GoBack(); + EXPECT_FALSE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK, FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1475,8 +1577,9 @@ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, FROM_HERE); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kJavaScriptExecution, - FROM_HERE); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution, + FROM_HERE); } // Similar to BackForwardCacheBrowserTest.EvictionOnJavaScriptExecution. @@ -1521,8 +1624,9 @@ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, FROM_HERE); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kJavaScriptExecution, - FROM_HERE); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -1563,8 +1667,9 @@ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, FROM_HERE); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kJavaScriptExecution, - FROM_HERE); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution, + FROM_HERE); } // Similar to BackForwardCacheBrowserTest.EvictionOnJavaScriptExecution, but @@ -1919,8 +2024,51 @@ ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, FROM_HERE); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kJavaScriptExecution, - FROM_HERE); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution, + FROM_HERE); +} + +// Similar to ReissuesNavigationIfEvictedDuringNavigation, except that +// BackForwardCache::Flush is the source of the eviction. +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, + FlushCacheDuringNavigationToCachedPage) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html")); + + // 1) Navigate to page A. + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + RenderFrameHostImpl* rfh_a1 = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_a1(rfh_a1); + + // 2) Navigate to page B. + EXPECT_TRUE(NavigateToURL(shell(), url_b)); + RenderFrameHostImpl* rfh_b2 = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_b2(rfh_b2); + EXPECT_FALSE(delete_observer_rfh_a1.deleted()); + EXPECT_TRUE(rfh_a1->is_in_back_forward_cache()); + EXPECT_NE(rfh_a1, rfh_b2); + + // 3) Start navigation to page A, and flush the cache during the navigation. + TestNavigationManager navigation_manager(shell()->web_contents(), url_a); + web_contents()->GetController().GoBack(); + + EXPECT_TRUE(navigation_manager.WaitForRequestStart()); + + // Flush the cache, which contains the document being navigated to. + web_contents()->GetController().GetBackForwardCache().Flush(); + + // The navigation should get canceled, then reissued; ultimately resulting in + // a successful navigation using a new RenderFrameHost. + navigation_manager.WaitForNavigationFinished(); + + // rfh_a should have been deleted, and page A navigated to normally. + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + delete_observer_rfh_a1.WaitUntilDeleted(); + EXPECT_TRUE(rfh_b2->is_in_back_forward_cache()); + RenderFrameHostImpl* rfh_a3 = current_frame_host(); + EXPECT_EQ(rfh_a3->GetLastCommittedURL(), url_a); } // Test that if the renderer process crashes while a document is in the @@ -1963,8 +2111,9 @@ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, FROM_HERE); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kRendererProcessKilled, - FROM_HERE); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kRendererProcessKilled, + FROM_HERE); } // The test is simulating a race condition. The scheduler tracked features are @@ -2192,6 +2341,13 @@ deleted.WaitUntilDeleted(); ExpectOutcomeIsEmpty(FROM_HERE); + + // 3) Go back to A. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures, + FROM_HERE); } class BackForwardCacheBrowserTestWithServiceWorkerEnabled @@ -2270,12 +2426,31 @@ } // Regression test for https://crbug.com/993337. +// +// A note about sharing BrowsingInstances and the BackForwardCache: +// +// We should never keep around more than one main frame that belongs to the same +// BrowsingInstance. When swapping two pages, when one is stored in the +// back-forward cache or one is restored from it, the current code expects the +// two to live in different BrowsingInstances. +// +// History navigation can recreate a page with the same BrowsingInstance as the +// one stored in the back-forward cache. This case must to be handled. When it +// happens, the back-forward cache page is evicted. +// +// Since cache eviction is asynchronous, it's is possible for two main frames +// belonging to the same BrowsingInstance to be alive for a brief period of time +// (the new page being navigated to, and a page in the cache, until it is +// destroyed asynchronously via eviction). +// +// The test below tests that the brief period of time where two main frames are +// alive in the same BrowsingInstance does not cause anything to blow up. IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NavigateToTwoPagesOnSameSite) { ASSERT_TRUE(embedded_test_server()->Start()); GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html")); GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html")); - GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html")); + GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html")); // 1) Navigate to A1. EXPECT_TRUE(NavigateToURL(shell(), url_a1)); @@ -2285,21 +2460,159 @@ RenderFrameHostImpl* rfh_a2 = current_frame_host(); RenderFrameDeletedObserver delete_rfh_a2(current_frame_host()); - // 3) Navigate to B1. - EXPECT_TRUE(NavigateToURL(shell(), url_b1)); + // 3) Navigate to B3. + EXPECT_TRUE(NavigateToURL(shell(), url_b3)); EXPECT_TRUE(rfh_a2->is_in_back_forward_cache()); - RenderFrameHostImpl* rfh_b1 = current_frame_host(); + RenderFrameHostImpl* rfh_b3 = current_frame_host(); // 4) Do a history navigation back to A1. web_contents()->GetController().GoToIndex(0); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); - EXPECT_TRUE(rfh_b1->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_b3->is_in_back_forward_cache()); - // As a result, rfh_a2 is deleted. The history navigation tried to restore an - // entry using the same BrowsingInstance. They both can't live together. + // Note that the frame for A1 gets created before A2 is deleted from the + // cache, so there will be a brief period where two the main frames (A1 and + // A2) are alive in the same BrowsingInstance/SiteInstance, at the same time. + // That is the scenario this test is covering. This used to cause a CHECK, + // because the two main frames shared a single RenderViewHost (no longer the + // case after https://crrev.com/c/1833616). + + // A2 should be evicted from the cache and asynchronously deleted, due to the + // cache size limit (B3 took its place in the cache). delete_rfh_a2.WaitUntilDeleted(); } +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, + NavigateToTwoPagesOnSameSiteWithSubframes) { + ASSERT_TRUE(embedded_test_server()->Start()); + // This test covers the same scenario as NavigateToTwoPagesOnSameSite, except + // the pages contain subframes: + // A1(B) -> A2(B(C)) -> D3 -> A1(B) + // + // The subframes shouldn't make a difference, so the expected behavior is the + // same as NavigateToTwoPagesOnSameSite. + GURL url_a1(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + GURL url_a2(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b(c))")); + GURL url_d3(embedded_test_server()->GetURL("d.com", "/title1.html")); + + // 1) Navigate to A1(B). + EXPECT_TRUE(NavigateToURL(shell(), url_a1)); + + // 2) Navigate to A2(B(C)). + EXPECT_TRUE(NavigateToURL(shell(), url_a2)); + RenderFrameHostImpl* rfh_a2 = current_frame_host(); + RenderFrameDeletedObserver delete_rfh_a2(current_frame_host()); + + // 3) Navigate to D3. + EXPECT_TRUE(NavigateToURL(shell(), url_d3)); + EXPECT_TRUE(rfh_a2->is_in_back_forward_cache()); + RenderFrameHostImpl* rfh_d3 = current_frame_host(); + + // 4) Do a history navigation back to A1(B). + web_contents()->GetController().GoToIndex(0); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + + // D3 takes A2(B(C))'s place in the cache. + EXPECT_TRUE(rfh_d3->is_in_back_forward_cache()); + delete_rfh_a2.WaitUntilDeleted(); +} + +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, + ConflictingBrowsingInstances) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html")); + GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A1. + EXPECT_TRUE(NavigateToURL(shell(), url_a1)); + + // 2) Navigate to A2. + EXPECT_TRUE(NavigateToURL(shell(), url_a2)); + RenderFrameHostImpl* rfh_a2 = current_frame_host(); + RenderFrameDeletedObserver delete_rfh_a2(current_frame_host()); + + // 3) Navigate to B3. + EXPECT_TRUE(NavigateToURL(shell(), url_b3)); + EXPECT_TRUE(rfh_a2->is_in_back_forward_cache()); + RenderFrameHostImpl* rfh_b3 = current_frame_host(); + // Make B3 ineligible for caching, so that navigating doesn't evict A2 + // due to the cache size limit. + content::BackForwardCache::DisableForRenderFrameHost( + rfh_b3, "BackForwardCacheBrowserTest"); + + // 4) Do a history navigation back to A1. At this point, A1 is going to have + // the same BrowsingInstance as A2. This should cause A2 to get + // evicted from the BackForwardCache due to its conflicting BrowsingInstance. + web_contents()->GetController().GoToIndex(0); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + EXPECT_EQ(current_frame_host()->GetLastCommittedURL(), url_a1); + delete_rfh_a2.WaitUntilDeleted(); +} + +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, + CanCacheMultiplesPagesOnSameDomain) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html")); + GURL url_a3(embedded_test_server()->GetURL("a.com", "/title2.html")); + GURL url_b4(embedded_test_server()->GetURL("b.com", "/title2.html")); + + // Increase the cache size so we're able to store multiple pages for the same + // site in the cache at once. + web_contents() + ->GetController() + .GetBackForwardCache() + .set_cache_size_limit_for_testing(3); + + // 1) Navigate to A1. + EXPECT_TRUE(NavigateToURL(shell(), url_a1)); + RenderFrameHostImpl* rfh_a1 = current_frame_host(); + + // 2) Navigate to B2. + EXPECT_TRUE(NavigateToURL(shell(), url_b2)); + RenderFrameHostImpl* rfh_b2 = current_frame_host(); + EXPECT_TRUE(rfh_a1->is_in_back_forward_cache()); + + // 3) Navigate to A3. + EXPECT_TRUE(NavigateToURL(shell(), url_a3)); + RenderFrameHostImpl* rfh_a3 = current_frame_host(); + EXPECT_TRUE(rfh_a1->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_b2->is_in_back_forward_cache()); + // A1 and A3 shouldn't be treated as the same site instance. + EXPECT_NE(rfh_a1->GetSiteInstance(), rfh_a3->GetSiteInstance()); + + // 4) Navigate to B4. + // Make sure we can store A1 and A3 in the cache at the same time. + EXPECT_TRUE(NavigateToURL(shell(), url_b4)); + RenderFrameHostImpl* rfh_b4 = current_frame_host(); + EXPECT_TRUE(rfh_a1->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_b2->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_a3->is_in_back_forward_cache()); + + // 5) Go back to A3. + // Make sure we can restore A3, while A1 remains in the cache. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + EXPECT_TRUE(rfh_a1->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_b2->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_b4->is_in_back_forward_cache()); + EXPECT_EQ(rfh_a3, current_frame_host()); + // B2 and B4 shouldn't be treated as the same site instance. + EXPECT_NE(rfh_b2->GetSiteInstance(), rfh_b4->GetSiteInstance()); + + // 6) Do a history navigation back to A1. + // Make sure we can restore A1, while coming from A3. + web_contents()->GetController().GoToIndex(0); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + EXPECT_TRUE(rfh_b2->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_b4->is_in_back_forward_cache()); + EXPECT_TRUE(rfh_a3->is_in_back_forward_cache()); + EXPECT_EQ(rfh_a1, current_frame_host()); +} + class GeolocationBackForwardCacheBrowserTest : public BackForwardCacheBrowserTest { protected: @@ -2485,7 +2798,8 @@ // 7) Go back to A. web_contents()->GetController().GoBack(); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); - ExpectEvicted(BackForwardCacheMetrics::EvictedReason::kTimeout, FROM_HERE); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason::kTimeout, + FROM_HERE); } IN_PROC_BROWSER_TEST_F( @@ -2512,7 +2826,9 @@ web_contents()->GetController().GoBack(); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectDisabledWithReason("DisabledByBackForwardCacheBrowserTest", FROM_HERE); - ExpectEvictedIsEmpty(FROM_HERE); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason:: + kDisableForRenderFrameHostCalled, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -2543,7 +2859,9 @@ web_contents()->GetController().GoBack(); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectDisabledWithReason("DisabledByBackForwardCacheBrowserTest", FROM_HERE); - ExpectEvictedIsEmpty(FROM_HERE); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason:: + kDisableForRenderFrameHostCalled, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -2571,7 +2889,9 @@ // 3) Go back to A. web_contents()->GetController().GoBack(); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); - ExpectEvictedIsEmpty(FROM_HERE); + ExpectNotRestored(BackForwardCacheMetrics::NotRestoredReason:: + kDisableForRenderFrameHostCalled, + FROM_HERE); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, @@ -2604,7 +2924,7 @@ web_contents()->GetController().GoBack(); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); ExpectDisabledWithReason("DisabledByBackForwardCacheBrowserTest", FROM_HERE); - ExpectEvictedIsEmpty(FROM_HERE); + ExpectNotRestoredIsEmpty(FROM_HERE); } // Confirm that same-document navigation and not history-navigation does not
diff --git a/content/browser/frame_host/back_forward_cache_impl.cc b/content/browser/frame_host/back_forward_cache_impl.cc index d625950b0..bcea784 100644 --- a/content/browser/frame_host/back_forward_cache_impl.cc +++ b/content/browser/frame_host/back_forward_cache_impl.cc
@@ -83,8 +83,8 @@ } uint64_t GetDisallowedFeatures(RenderFrameHostImpl* rfh) { - // TODO(lowell): Finalize disallowed feature list, and test for each - // disallowed feature. + // TODO(https://crbug.com/1015784): Finalize disallowed feature list, and test + // for each disallowed feature. constexpr uint64_t kAlwaysDisallowedFeatures = ToFeatureBit(WebSchedulerTrackedFeature::kWebRTC) | ToFeatureBit(WebSchedulerTrackedFeature::kContainsPlugins) | @@ -175,7 +175,7 @@ BackForwardCacheImpl::Entry::~Entry() {} std::string BackForwardCacheImpl::CanStoreDocumentResult::ToString() { - using Reason = BackForwardCacheMetrics::CanNotStoreDocumentReason; + using Reason = BackForwardCacheMetrics::NotRestoredReason; if (can_store) return "Yes"; @@ -206,6 +206,26 @@ return "No: HTTP method is not GET"; case Reason::kSubframeIsNavigating: return "No: subframe navigation is in progress"; + case Reason::kTimeout: + return "No: timeout"; + case Reason::kCacheLimit: + return "No: cache limit"; + case Reason::kJavaScriptExecution: + return "No: JavaScript execution"; + case Reason::kRendererProcessKilled: + return "No: renderer process is killed"; + case Reason::kRendererProcessCrashed: + return "No: renderer process crashed"; + case Reason::kDialog: + return "No: dialog"; + case Reason::kGrantedMediaStreamAccess: + return "No: granted media stream access"; + case Reason::kSchedulerTrackedFeatureUsed: + return "No: scheduler tracked feature is used"; + case Reason::kConflictingBrowsingInstance: + return "No: conflicting BrowsingInstance"; + case Reason::kCacheFlushed: + return "No: cache flushed"; } } @@ -221,7 +241,7 @@ BackForwardCacheImpl::CanStoreDocumentResult BackForwardCacheImpl::CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason reason) { + BackForwardCacheMetrics::NotRestoredReason reason) { return CanStoreDocumentResult(false, reason, 0); } @@ -229,14 +249,13 @@ BackForwardCacheImpl::CanStoreDocumentResult::NoDueToFeatures( uint64_t blocklisted_features) { return CanStoreDocumentResult( - false, - BackForwardCacheMetrics::CanNotStoreDocumentReason::kBlocklistedFeatures, + false, BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures, blocklisted_features); } BackForwardCacheImpl::CanStoreDocumentResult::CanStoreDocumentResult( bool can_store, - base::Optional<BackForwardCacheMetrics::CanNotStoreDocumentReason> reason, + base::Optional<BackForwardCacheMetrics::NotRestoredReason> reason, uint64_t blocklisted_features) : can_store(can_store), reason(reason), @@ -278,13 +297,12 @@ // Use the BackForwardCache only for the main frame. if (rfh->GetParent()) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason::kNotMainFrame); + BackForwardCacheMetrics::NotRestoredReason::kNotMainFrame); } if (!IsBackForwardCacheEnabled() || is_disabled_for_testing_) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason:: - kBackForwardCacheDisabled); + BackForwardCacheMetrics::NotRestoredReason::kBackForwardCacheDisabled); } // Two pages in the same BrowsingInstance can script each other. When a page @@ -298,7 +316,7 @@ // BrowsingInstance. if (rfh->GetSiteInstance()->GetRelatedActiveContentsCount() != 0) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason:: + BackForwardCacheMetrics::NotRestoredReason:: kRelatedActiveContentsExist); } @@ -306,27 +324,26 @@ // Note that for error pages, |last_http_status_code| is equal to 0. if (rfh->last_http_status_code() != net::HTTP_OK) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason::kHTTPStatusNotOK); + BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK); } // Only store documents that were fetched via HTTP GET method. if (rfh->last_http_method() != net::HttpRequestHeaders::kGetMethod) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason::kHTTPMethodNotGET); + BackForwardCacheMetrics::NotRestoredReason::kHTTPMethodNotGET); } // Do not store main document with non HTTP/HTTPS URL scheme. In particular, // this excludes the new tab page. if (!rfh->GetLastCommittedURL().SchemeIsHTTPOrHTTPS()) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason:: - kSchemeNotHTTPOrHTTPS); + BackForwardCacheMetrics::NotRestoredReason::kSchemeNotHTTPOrHTTPS); } // Only store documents that have URLs allowed through experiment. if (!IsAllowed(rfh->GetLastCommittedURL())) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason::kDomainNotAllowed); + BackForwardCacheMetrics::NotRestoredReason::kDomainNotAllowed); } return CanStoreRenderFrameHost(rfh); @@ -336,22 +353,22 @@ // can be cached. BackForwardCacheImpl::CanStoreDocumentResult BackForwardCacheImpl::CanStoreRenderFrameHost(RenderFrameHostImpl* rfh) { - if (!rfh->dom_content_loaded()) + if (!rfh->dom_content_loaded()) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason::kLoading); + BackForwardCacheMetrics::NotRestoredReason::kLoading); + } // If the rfh has ever granted media access, prevent it from entering cache. // TODO(crbug.com/989379): Consider only blocking when there's an active // media stream. if (rfh->was_granted_media_access()) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason:: - kWasGrantedMediaAccess); + BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess); } if (rfh->is_back_forward_cache_disallowed()) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason:: + BackForwardCacheMetrics::NotRestoredReason:: kDisableForRenderFrameHostCalled); } @@ -369,8 +386,7 @@ // Do not cache if we have navigations in any of the subframes. if (rfh->GetParent() && has_navigation_request) { return CanStoreDocumentResult::No( - BackForwardCacheMetrics::CanNotStoreDocumentReason:: - kSubframeIsNavigating); + BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating); } for (size_t i = 0; i < rfh->child_count(); i++) { @@ -402,7 +418,7 @@ continue; if (++available_count > size_limit) { stored_entry->render_frame_host->EvictFromBackForwardCacheWithReason( - BackForwardCacheMetrics::EvictedReason::kCacheLimit); + BackForwardCacheMetrics::NotRestoredReason::kCacheLimit); } } } @@ -449,9 +465,27 @@ void BackForwardCacheImpl::Flush() { TRACE_EVENT0("navigation", "BackForwardCache::Flush"); + for (std::unique_ptr<Entry>& entry : entries_) { + entry->render_frame_host->EvictFromBackForwardCacheWithReason( + BackForwardCacheMetrics::NotRestoredReason::kCacheFlushed); + } +} + +void BackForwardCacheImpl::Shutdown() { entries_.clear(); } +void BackForwardCacheImpl::EvictFramesInRelatedSiteInstances( + SiteInstance* site_instance) { + for (std::unique_ptr<Entry>& entry : entries_) { + if (entry->render_frame_host->GetSiteInstance()->IsRelatedSiteInstance( + site_instance)) + entry->render_frame_host->EvictFromBackForwardCacheWithReason( + BackForwardCacheMetrics::NotRestoredReason:: + kConflictingBrowsingInstance); + } +} + void BackForwardCacheImpl::PostTaskToDestroyEvictedFrames() { base::PostTask(FROM_HERE, {BrowserThread::UI}, base::BindOnce(&BackForwardCacheImpl::DestroyEvictedFrames,
diff --git a/content/browser/frame_host/back_forward_cache_impl.h b/content/browser/frame_host/back_forward_cache_impl.h index ff6a46b..4c5ff272 100644 --- a/content/browser/frame_host/back_forward_cache_impl.h +++ b/content/browser/frame_host/back_forward_cache_impl.h
@@ -27,6 +27,7 @@ class RenderFrameHostImpl; class RenderFrameProxyHost; class RenderViewHostImpl; +class SiteInstance; // BackForwardCache: // @@ -77,12 +78,13 @@ ~CanStoreDocumentResult(); bool can_store; - base::Optional<BackForwardCacheMetrics::CanNotStoreDocumentReason> reason; + // TODO(hajimehoshi): Accept multiple reasons. + base::Optional<BackForwardCacheMetrics::NotRestoredReason> reason; uint64_t blocklisted_features; static CanStoreDocumentResult Yes(); static CanStoreDocumentResult No( - BackForwardCacheMetrics::CanNotStoreDocumentReason reason); + BackForwardCacheMetrics::NotRestoredReason reason); static CanStoreDocumentResult NoDueToFeatures(uint64_t features); std::string ToString(); @@ -92,8 +94,7 @@ private: CanStoreDocumentResult( bool can_store, - base::Optional<BackForwardCacheMetrics::CanNotStoreDocumentReason> - reason, + base::Optional<BackForwardCacheMetrics::NotRestoredReason> reason, uint64_t blocklisted_features); }; @@ -128,9 +129,17 @@ // knowing its |navigation_entry_id|. Returns nullptr when none is found. std::unique_ptr<Entry> RestoreEntry(int navigation_entry_id); - // Remove all entries from the BackForwardCache. + // Evict all entries from the BackForwardCache. void Flush(); + // Evict all cached pages in the same BrowsingInstance as + // |site_instance|. + void EvictFramesInRelatedSiteInstances(SiteInstance* site_instance); + + // Immediately deletes all frames in the cache. This should only be called + // when WebContents is being destroyed. + void Shutdown(); + // Posts a task to destroy all frames in the BackForwardCache that have been // marked as evicted. void PostTaskToDestroyEvictedFrames();
diff --git a/content/browser/frame_host/back_forward_cache_metrics.cc b/content/browser/frame_host/back_forward_cache_metrics.cc index 871a700d..a7b5658d 100644 --- a/content/browser/frame_host/back_forward_cache_metrics.cc +++ b/content/browser/frame_host/back_forward_cache_metrics.cc
@@ -98,11 +98,10 @@ NavigationRequest* navigation) { bool is_history_navigation = navigation->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK; - if (navigation->IsInMainFrame() && !navigation->IsSameDocument() && - is_history_navigation) { - RecordMetricsForHistoryNavigationCommit(navigation); - disallowed_reasons_.clear(); - evicted_reason_ = base::nullopt; + if (navigation->IsInMainFrame() && !navigation->IsSameDocument()) { + if (is_history_navigation) + RecordMetricsForHistoryNavigationCommit(navigation); + not_restored_reasons_.reset(); } if (last_committed_main_frame_navigation_id_ != -1 && @@ -178,14 +177,14 @@ } } -void BackForwardCacheMetrics::MarkDisableForRenderFrameHost( - const base::StringPiece& reason) { - disallowed_reasons_.push_back(reason.as_string()); +void BackForwardCacheMetrics::MarkNotRestoredWithReason( + NotRestoredReason reason) { + not_restored_reasons_.set(static_cast<size_t>(reason)); } -void BackForwardCacheMetrics::MarkEvictedFromBackForwardCacheWithReason( - BackForwardCacheMetrics::EvictedReason reason) { - evicted_reason_ = reason; +void BackForwardCacheMetrics::MarkDisableForRenderFrameHost( + const base::StringPiece& reason) { + disallowed_reasons_.insert(reason.as_string()); } void BackForwardCacheMetrics::RecordMetricsForHistoryNavigationCommit( @@ -199,15 +198,20 @@ BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason::kRestored); } - // TODO(hajimehoshi): Do not record the outcome when the experient condition - // does not match. + // TODO(hajimehoshi): By |BackForwardCache::IsAllowed(navigation->GetURL())|, + // check whether the page matches the experiment condition, and do not record + // anything in this case. + UMA_HISTOGRAM_ENUMERATION("BackForwardCache.HistoryNavigationOutcome", outcome); - if (evicted_reason_.has_value()) { + for (int i = 0; i <= static_cast<int>(NotRestoredReason::kMaxValue); i++) { + if (!not_restored_reasons_.test(static_cast<size_t>(i))) + continue; + DCHECK(!navigation->IsServedFromBackForwardCache()); UMA_HISTOGRAM_ENUMERATION( - "BackForwardCache.HistoryNavigationOutcome.EvictedReason", - evicted_reason_.value()); + "BackForwardCache.HistoryNavigationOutcome.NotRestoredReason", + static_cast<NotRestoredReason>(i)); } for (const std::string& reason : disallowed_reasons_) {
diff --git a/content/browser/frame_host/back_forward_cache_metrics.h b/content/browser/frame_host/back_forward_cache_metrics.h index 62e95f5..0e0613c 100644 --- a/content/browser/frame_host/back_forward_cache_metrics.h +++ b/content/browser/frame_host/back_forward_cache_metrics.h
@@ -5,6 +5,9 @@ #ifndef CONTENT_BROWSER_FRAME_HOST_BACK_FORWARD_CACHE_METRICS_H_ #define CONTENT_BROWSER_FRAME_HOST_BACK_FORWARD_CACHE_METRICS_H_ +#include <bitset> +#include <set> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/optional.h" @@ -32,19 +35,32 @@ class BackForwardCacheMetrics : public base::RefCounted<BackForwardCacheMetrics> { public: - enum class CanNotStoreDocumentReason : uint8_t { - kNotMainFrame, - kBackForwardCacheDisabled, - kRelatedActiveContentsExist, - kHTTPStatusNotOK, - kSchemeNotHTTPOrHTTPS, - kLoading, - kWasGrantedMediaAccess, - kBlocklistedFeatures, - kDisableForRenderFrameHostCalled, - kDomainNotAllowed, - kHTTPMethodNotGET, - kSubframeIsNavigating + // Please keep in sync with BackForwardCacheNotRestoredReason in + // tools/metrics/histograms/enums.xml. These values should not be renumbered. + enum class NotRestoredReason : uint8_t { + kNotMainFrame = 0, + kBackForwardCacheDisabled = 1, + kRelatedActiveContentsExist = 2, + kHTTPStatusNotOK = 3, + kSchemeNotHTTPOrHTTPS = 4, + kLoading = 5, + kWasGrantedMediaAccess = 6, + kBlocklistedFeatures = 7, + kDisableForRenderFrameHostCalled = 8, + kDomainNotAllowed = 9, + kHTTPMethodNotGET = 10, + kSubframeIsNavigating = 11, + kTimeout = 12, + kCacheLimit = 13, + kJavaScriptExecution = 14, + kRendererProcessKilled = 15, + kRendererProcessCrashed = 16, + kDialog = 17, + kGrantedMediaStreamAccess = 18, + kSchedulerTrackedFeatureUsed = 19, + kConflictingBrowsingInstance = 20, + kCacheFlushed = 21, + kMaxValue = kCacheFlushed, }; // Please keep in sync with BackForwardCacheHistoryNavigationOutcome in @@ -55,20 +71,6 @@ kMaxValue = kNotRestored, }; - // Please keep in sync with BackForwardCacheEvictedReason in - // tools/metrics/histograms/enums.xml. These values should not be renumbered. - enum class EvictedReason { - kTimeout = 0, - kCacheLimit = 1, - kJavaScriptExecution = 2, - kRendererProcessKilled = 3, - kRendererProcessCrashed = 4, - kDialog = 5, - kGrantedMediaStreamAccess = 6, - kSchedulerTrackedFeatureUsed = 7, - kMaxValue = kSchedulerTrackedFeatureUsed, - }; - // Please keep in sync with BackForwardCacheEvictedAfterDocumentRestoredReason // in tools/metrics/histograms/enums.xml. These values should not be // renumbered. @@ -121,10 +123,9 @@ // placed in the back-forward cache. void RecordFeatureUsage(RenderFrameHostImpl* main_frame); - // Marks when the page is evicted with the reason. This information is useful - // e.g., to know the major cause of eviction. - void MarkEvictedFromBackForwardCacheWithReason( - BackForwardCacheMetrics::EvictedReason reason); + // Marks when the page is not cached, or evicted. This information is useful + // e.g., to prioritize the tasks to improve cache-hit rate. + void MarkNotRestoredWithReason(NotRestoredReason reason); // Marks the frame disabled the back forward cache with the reason. void MarkDisableForRenderFrameHost(const base::StringPiece& reason); @@ -170,8 +171,12 @@ base::Optional<base::TimeTicks> started_navigation_timestamp_; base::Optional<base::TimeTicks> navigated_away_from_main_document_timestamp_; - std::vector<std::string> disallowed_reasons_; - base::Optional<EvictedReason> evicted_reason_; + std::bitset<static_cast<size_t>(NotRestoredReason::kMaxValue) + 1ul> + not_restored_reasons_; + + // The reasons given at BackForwardCache::DisableForRenderFrameHost. These are + // a further breakdown of NotRestoredReason::kDisableForRenderFrameHostCalled. + std::set<std::string> disallowed_reasons_; DISALLOW_COPY_AND_ASSIGN(BackForwardCacheMetrics); };
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 2ab2b0c0..ce88050 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -2558,18 +2558,30 @@ return; } - // By design, a page in the BackForwardCache is alone in its BrowsingInstance. - // History navigation might try to reuse a specific SiteInstance, already used - // by a page in the cache. This must not happen. It would fail creating the - // RenderFrame, because only one main document can live there. For this - // reason, the BackForwardCache is flushed. - // TODO(arthursonzogni): Flushing the entire cache is a bit overkill, this can - // be refined to only delete the page (if any) using the same - // BrowsingInstance. + // History navigation might try to reuse a specific BrowsingInstance, already + // used by a page in the cache. To avoid having two different main frames that + // live in the same BrowsingInstance, evict the all pages with this + // BrowsingInstance from the cache. + // + // For example, take the following scenario: + // + // A1 = Some page on a.com + // A2 = Some other page on a.com + // B3 = An uncacheable page on b.com + // + // Then the following navigations occur: + // A1->A2->B3->A1 + // On the navigation from B3 to A1, A2 will remain in the cache (B3 doesn't + // take its place) and A1 will be created in the same BrowsingInstance (and + // SiteInstance), as A2. + // + // If we didn't do anything, both A1 and A2 would remain alive in the same + // BrowsingInstance/SiteInstance, which is unsupported by + // RenderFrameHostManager::CommitPending(). To avoid this conundrum, we evict + // A2 from the cache. if (pending_entry_->site_instance()) { - SiteInstance* current = root->current_frame_host()->GetSiteInstance(); - if (!current->IsRelatedSiteInstance(pending_entry_->site_instance())) - back_forward_cache_.Flush(); + back_forward_cache_.EvictFramesInRelatedSiteInstances( + pending_entry_->site_instance()); } // If we were navigating to a slow-to-commit page, and the user performs
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 6f34a9896..9eae307 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -1355,9 +1355,11 @@ void NavigationRequest::OnRequestRedirected( const net::RedirectInfo& redirect_info, const scoped_refptr<network::ResourceResponse>& response_head) { + // Sanity check - this can only be set at commit time. + DCHECK(!auth_challenge_info_); + response_head_ = response_head; ssl_info_ = response_head->head.ssl_info; - auth_challenge_info_ = response_head->head.auth_challenge_info; // Reset the page state as it can no longer be used at commit time since the // navigation was redirected. @@ -3201,24 +3203,6 @@ starting_site_instance_->GetIsolationContext(), common_params_->url); } -net::NetworkIsolationKey NavigationRequest::GetNetworkIsolationKey() const { - if (network_isolation_key_) - return network_isolation_key_.value(); - - // If this is a top-frame navigation, then use the origin of the url (and - // update it as redirects happen). If this is a subframe navigation, get the - // URL from the top frame. - // TODO(crbug.com/979296): Consider changing this code to copy an origin - // instead of creating one from a URL which lacks opacity information. - url::Origin frame_origin = url::Origin::Create(common_params_->url); - url::Origin top_frame_origin = - frame_tree_node_->IsMainFrame() - ? frame_origin - : frame_tree_node_->frame_tree()->root()->current_origin(); - - return net::NetworkIsolationKey(top_frame_origin, frame_origin); -} - // TODO(zetamoo): Try to merge this function inside its callers. void NavigationRequest::UpdateStateFollowingRedirect( const GURL& new_referrer_url, @@ -3688,6 +3672,24 @@ return auth_challenge_info_; } +net::NetworkIsolationKey NavigationRequest::GetNetworkIsolationKey() { + if (network_isolation_key_) + return network_isolation_key_.value(); + + // If this is a top-frame navigation, then use the origin of the url (and + // update it as redirects happen). If this is a subframe navigation, get the + // URL from the top frame. + // TODO(crbug.com/979296): Consider changing this code to copy an origin + // instead of creating one from a URL which lacks opacity information. + url::Origin frame_origin = url::Origin::Create(common_params_->url); + url::Origin top_frame_origin = + frame_tree_node_->IsMainFrame() + ? frame_origin + : frame_tree_node_->frame_tree()->root()->current_origin(); + + return net::NetworkIsolationKey(top_frame_origin, frame_origin); +} + bool NavigationRequest::HasSubframeNavigationEntryCommitted() { DCHECK(!frame_tree_node_->IsMainFrame()); DCHECK(handle_state_ == DID_COMMIT || handle_state_ == DID_COMMIT_ERROR_PAGE);
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index 281aeacf..3a19e57 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h
@@ -227,6 +227,7 @@ net::HttpResponseInfo::ConnectionInfo GetConnectionInfo() override; const base::Optional<net::SSLInfo>& GetSSLInfo() override; const base::Optional<net::AuthChallengeInfo>& GetAuthChallengeInfo() override; + net::NetworkIsolationKey GetNetworkIsolationKey() override; void RegisterThrottleForTesting( std::unique_ptr<NavigationThrottle> navigation_throttle) override; bool IsDeferredForTesting() override; @@ -747,11 +748,6 @@ // Note: |site_url_| should only be updated with the result of this function. GURL GetSiteForCommonParamsURL() const; - // Returns the network isolation key for this NavigationRequest. If - // |network_isolation_key_| is empty, the key will be based off request url - // origin and top frame origin. - net::NetworkIsolationKey GetNetworkIsolationKey() const; - // Updates the state of the navigation handle after encountering a server // redirect. void UpdateStateFollowingRedirect(const GURL& new_referrer_url,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 120b424..3c62948 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1269,7 +1269,7 @@ FROM_HERE, evict_after, base::BindOnce(&RenderFrameHostImpl::EvictFromBackForwardCacheWithReason, weak_ptr_factory_.GetWeakPtr(), - BackForwardCacheMetrics::EvictedReason::kTimeout)); + BackForwardCacheMetrics::NotRestoredReason::kTimeout)); } void RenderFrameHostImpl::DisallowBackForwardCache() { @@ -1281,7 +1281,7 @@ void RenderFrameHostImpl::OnGrantedMediaStreamAccess() { was_granted_media_access_ = true; MaybeEvictFromBackForwardCache( - BackForwardCacheMetrics::EvictedReason::kGrantedMediaStreamAccess); + BackForwardCacheMetrics::NotRestoredReason::kGrantedMediaStreamAccess); } void RenderFrameHostImpl::OnPortalActivated( @@ -1882,8 +1882,10 @@ if (is_in_back_forward_cache_) { EvictFromBackForwardCacheWithReason( info.status == base::TERMINATION_STATUS_PROCESS_CRASHED - ? BackForwardCacheMetrics::EvictedReason::kRendererProcessCrashed - : BackForwardCacheMetrics::EvictedReason::kRendererProcessKilled); + ? BackForwardCacheMetrics::NotRestoredReason:: + kRendererProcessCrashed + : BackForwardCacheMetrics::NotRestoredReason:: + kRendererProcessKilled); return; } @@ -2555,7 +2557,7 @@ renderer_reported_scheduler_tracked_features_ = features_mask; MaybeEvictFromBackForwardCache( - BackForwardCacheMetrics::EvictedReason::kSchedulerTrackedFeatureUsed); + BackForwardCacheMetrics::NotRestoredReason::kSchedulerTrackedFeatureUsed); } void RenderFrameHostImpl::OnSchedulerTrackedFeatureUsed( @@ -2565,7 +2567,7 @@ 1 << static_cast<uint64_t>(feature); MaybeEvictFromBackForwardCache( - BackForwardCacheMetrics::EvictedReason::kSchedulerTrackedFeatureUsed); + BackForwardCacheMetrics::NotRestoredReason::kSchedulerTrackedFeatureUsed); } bool RenderFrameHostImpl::IsFrozen() { @@ -3115,7 +3117,7 @@ // If a dialog tries to show for a document in the BackForwardCache, evict it. if (is_in_back_forward_cache_) { EvictFromBackForwardCacheWithReason( - BackForwardCacheMetrics::EvictedReason::kDialog); + BackForwardCacheMetrics::NotRestoredReason::kDialog); return; } @@ -3701,11 +3703,11 @@ // TODO(hajimehoshi): This function should take the reason from the renderer // side. EvictFromBackForwardCacheWithReason( - BackForwardCacheMetrics::EvictedReason::kJavaScriptExecution); + BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution); } void RenderFrameHostImpl::EvictFromBackForwardCacheWithReason( - base::Optional<BackForwardCacheMetrics::EvictedReason> reason) { + base::Optional<BackForwardCacheMetrics::NotRestoredReason> reason) { DCHECK(IsBackForwardCacheEnabled()); if (is_evicted_from_back_forward_cache_) @@ -3723,7 +3725,7 @@ // |is_in_back_forward_cache()| is false. BackForwardCacheMetrics* metrics = top_document->GetBackForwardCacheMetrics(); if (is_in_back_forward_cache() && reason && metrics) - metrics->MarkEvictedFromBackForwardCacheWithReason(reason.value()); + metrics->MarkNotRestoredWithReason(reason.value()); if (!in_back_forward_cache) { BackForwardCacheMetrics::RecordEvictedAfterDocumentRestored( @@ -7890,7 +7892,7 @@ } void RenderFrameHostImpl::MaybeEvictFromBackForwardCache( - BackForwardCacheMetrics::EvictedReason reason) { + BackForwardCacheMetrics::NotRestoredReason reason) { if (!is_in_back_forward_cache_) return;
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index a46428f..54c01d4 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -323,7 +323,7 @@ const AXEventNotificationDetails& details); void EvictFromBackForwardCacheWithReason( - base::Optional<BackForwardCacheMetrics::EvictedReason> reason); + base::Optional<BackForwardCacheMetrics::NotRestoredReason> reason); // IPC::Sender bool Send(IPC::Message* msg) override; @@ -1928,7 +1928,7 @@ // Evicts the document from the BackForwardCache if it is in the cache, // and ineligible for caching. void MaybeEvictFromBackForwardCache( - BackForwardCacheMetrics::EvictedReason reason); + BackForwardCacheMetrics::NotRestoredReason reason); // Helper for handling download-related IPCs. void DownloadUrl(
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc index 7c71c3d..7665f43d 100644 --- a/content/browser/frame_host/render_frame_host_manager.cc +++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -474,6 +474,13 @@ // RenderFrameHost should not be trying to commit a navigation. old_render_frame_host->ResetNavigationRequests(); + NavigationEntryImpl* last_committed_entry = + delegate_->GetControllerForRenderManager().GetLastCommittedEntry(); + BackForwardCacheMetrics* old_page_back_forward_cache_metrics = + (!old_render_frame_host->GetParent() && last_committed_entry) + ? last_committed_entry->back_forward_cache_metrics() + : nullptr; + // Record the metrics about the state of the old main frame at the moment when // we navigate away from it as it matters for whether the page is eligible for // being put into back-forward cache. @@ -484,16 +491,9 @@ // // TODO(altimin, crbug.com/933147): Remove this logic after we are done with // implementing back-forward cache. - if (!old_render_frame_host->GetParent()) { - if (NavigationEntryImpl* last_committed_entry = - delegate_->GetControllerForRenderManager() - .GetLastCommittedEntry()) { - if (last_committed_entry->back_forward_cache_metrics()) { - last_committed_entry->back_forward_cache_metrics()->RecordFeatureUsage( - old_render_frame_host.get()); - } - } - } + if (old_page_back_forward_cache_metrics) + old_page_back_forward_cache_metrics->RecordFeatureUsage( + old_render_frame_host.get()); // BackForwardCache: // @@ -543,6 +543,14 @@ back_forward_cache.StoreEntry(std::move(entry)); return; } + + if (old_page_back_forward_cache_metrics) { + // TODO(hajimehoshi): For code readability, BackForwardCacheMetrics should + // take CanStoreDocumentResult directly and rename + // MarkNotRestoredWithReason to DidNotStoreDocument. + old_page_back_forward_cache_metrics->MarkNotRestoredWithReason( + can_store.reason.value()); + } } // Create a replacement proxy for the old RenderFrameHost. (There should not
diff --git a/content/browser/interface_provider_filtering.cc b/content/browser/interface_provider_filtering.cc index 0eb8a8f..f6f7aa4 100644 --- a/content/browser/interface_provider_filtering.cc +++ b/content/browser/interface_provider_filtering.cc
@@ -25,7 +25,7 @@ service_manager::mojom::InterfaceProviderRequest request, service_manager::mojom::InterfaceProviderPtr provider) { RenderProcessHost* process = RenderProcessHost::FromID(process_id); - if (!process) + if (!process || !process->IsInitializedAndNotDead()) return; service_manager::Connector* connector =
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 311756e..68c4f29 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3933,6 +3933,41 @@ } // static +RenderProcessHost* RenderProcessHostImpl::GetUnusedProcessHostForServiceWorker( + SiteInstanceImpl* site_instance) { + DCHECK(site_instance->is_for_service_worker()); + if (site_instance->process_reuse_policy() != + SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE) { + return nullptr; + } + + auto& spare_process_manager = SpareRenderProcessHostManager::GetInstance(); + iterator iter(AllHostsIterator()); + while (!iter.IsAtEnd()) { + auto* host = iter.GetCurrentValue(); + // This function tries to choose the process that will be chosen by a + // navigation that will use the service worker that is being started. Prefer + // to not take the spare process host, since if the navigation is out of the + // New Tab Page on Android, it will be using the existing NTP process + // instead of the spare process. If this function doesn't find a suitable + // process, the spare can still be chosen when + // MaybeTakeSpareRenderProcessHost() is called later. + bool is_spare = (host == spare_process_manager.spare_render_process_host()); + + if (!is_spare && iter.GetCurrentValue()->MayReuseHost() && + iter.GetCurrentValue()->IsUnused() && + RenderProcessHostImpl::IsSuitableHost( + iter.GetCurrentValue(), site_instance->GetBrowserContext(), + site_instance->GetIsolationContext(), site_instance->GetSiteURL(), + site_instance->lock_url())) { + return host; + } + iter.Advance(); + } + return nullptr; +} + +// static bool RenderProcessHost::ShouldUseProcessPerSite(BrowserContext* browser_context, const GURL& url) { // Returns true if we should use the process-per-site model. This will be @@ -4064,6 +4099,13 @@ features::kProcessSharingWithStrictSiteInstances)); } + // If a process hasn't been selected yet, and the site instance is for a + // service worker, try to use an unused process host. One might have been + // created for a navigation and this will let the navigation and the service + // worker share the same process. + if (!render_process_host && is_unmatched_service_worker) + render_process_host = GetUnusedProcessHostForServiceWorker(site_instance); + // See if the spare RenderProcessHost can be used. auto& spare_process_manager = SpareRenderProcessHostManager::GetInstance(); bool spare_was_taken = false;
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index b76dc4a1..4c19196 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -715,6 +715,22 @@ FRIEND_TEST_ALL_PREFIXES(RenderProcessHostUnitTest, GuestsAreNotSuitableHosts); + // Returns an existing RenderProcessHost that has not yet been used and is + // suitable for the given |site_instance|, or null if no such process host + // exists. + // + // This function is used when finding a process for a service worker. The + // idea is to choose the process that will be chosen by a navigation that will + // use the service worker. While navigations typically try to choose the + // process with the relevant service worker (using + // UnmatchedServiceWorkerProcessTracker), navigations out of the Android New + // Tab Page use a SiteInstance with an empty URL by design in order to choose + // the NTP process, and do not go through the typical matching algorithm. The + // goal of this function is to return the NTP process so the service worker + // can also use it. + static RenderProcessHost* GetUnusedProcessHostForServiceWorker( + SiteInstanceImpl* site_instance); + // Returns a RenderProcessHost that is rendering a URL corresponding to // |site_instance| in one of its frames, or that is expecting a navigation to // that SiteInstance.
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 45a587b8..0cdd7417 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -847,11 +847,11 @@ // 7. Browser: parent RenderWidgetHost (We're here if |is_child_frame|.) // 8. IPC -> WidgetMsg_UpdateVisualProperties // 9. Renderer B: child RenderWidget - visual_properties.page_scale_factor = - properties_from_parent_frame_.page_scale_factor; - visual_properties.is_pinch_gesture_active = - properties_from_parent_frame_.is_pinch_gesture_active; if (is_child_frame) { + visual_properties.page_scale_factor = + properties_from_parent_frame_.page_scale_factor; + visual_properties.is_pinch_gesture_active = + properties_from_parent_frame_.is_pinch_gesture_active; visual_properties.compositor_viewport_pixel_rect = properties_from_parent_frame_.compositor_viewport;
diff --git a/content/browser/service_worker/service_worker_process_browsertest.cc b/content/browser/service_worker/service_worker_process_browsertest.cc new file mode 100644 index 0000000..502fbe8 --- /dev/null +++ b/content/browser/service_worker/service_worker_process_browsertest.cc
@@ -0,0 +1,205 @@ +// Copyright 2019 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 "base/command_line.h" +#include "base/memory/scoped_refptr.h" +#include "base/run_loop.h" +#include "base/test/bind_test_util.h" +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/common/content_client.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/shell/browser/shell.h" +#include "content/test/test_content_browser_client.h" +#include "net/dns/mock_host_resolver.h" + +// This file has tests involving render process selection for service workers. + +namespace content { + +class ServiceWorkerProcessBrowserTest + : public ContentBrowserTest, + public ::testing::WithParamInterface<bool> { + public: + ServiceWorkerProcessBrowserTest() = default; + ~ServiceWorkerProcessBrowserTest() override = default; + + ServiceWorkerProcessBrowserTest(const ServiceWorkerProcessBrowserTest&) = + delete; + ServiceWorkerProcessBrowserTest& operator=( + const ServiceWorkerProcessBrowserTest&) = delete; + + void SetUpOnMainThread() override { + // Support multiple sites on the test server. + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->Start()); + + StoragePartition* partition = BrowserContext::GetDefaultStoragePartition( + shell()->web_contents()->GetBrowserContext()); + wrapper_ = static_cast<ServiceWorkerContextWrapper*>( + partition->GetServiceWorkerContext()); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + if (SitePerProcess()) + command_line->AppendSwitch(switches::kSitePerProcess); + } + + protected: + bool SitePerProcess() const { return GetParam(); } + + // Registers a service worker and then tears down the process it used, for a + // clean slate going forward. + void RegisterServiceWorker() { + // Load a page that registers a service worker. + Shell* start_shell = CreateBrowser(); + ASSERT_TRUE(NavigateToURL( + start_shell, embedded_test_server()->GetURL( + "/service_worker/create_service_worker.html"))); + ASSERT_EQ("DONE", + EvalJs(start_shell, "register('fetch_event_pass_through.js');")); + + auto* host = RenderProcessHost::FromID(GetServiceWorkerProcessId()); + ASSERT_TRUE(host); + RenderProcessHostWatcher exit_watcher( + host, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + + // Tear down the page. + start_shell->Close(); + + // Stop the service worker. The process should exit. + base::RunLoop loop; + wrapper()->StopAllServiceWorkers(loop.QuitClosure()); + loop.Run(); + exit_watcher.Wait(); + } + + // Returns the number of running service workers. + size_t GetRunningServiceWorkerCount() { + return wrapper()->GetRunningServiceWorkerInfos().size(); + } + + // Returns the process id of the running service worker. There must be exactly + // one service worker running. + int GetServiceWorkerProcessId() { + const base::flat_map<int64_t, ServiceWorkerRunningInfo>& infos = + wrapper()->GetRunningServiceWorkerInfos(); + DCHECK_EQ(infos.size(), 1u); + const ServiceWorkerRunningInfo& info = infos.begin()->second; + return info.render_process_id; + } + + ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); } + + WebContentsImpl* web_contents() { + return static_cast<WebContentsImpl*>(shell()->web_contents()); + } + + RenderFrameHostImpl* current_frame_host() { + return web_contents()->GetFrameTree()->root()->current_frame_host(); + } + + private: + scoped_refptr<ServiceWorkerContextWrapper> wrapper_; +}; + +// Tests that a service worker started due to a navigation shares the same +// process as the navigation. +IN_PROC_BROWSER_TEST_P(ServiceWorkerProcessBrowserTest, + ServiceWorkerAndPageShareProcess) { + // Register the service worker. + RegisterServiceWorker(); + + // Navigate to a page in the service worker's scope. + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("/service_worker/empty.html"))); + + // The page and service worker should be in the same process. + int page_process_id = current_frame_host()->GetProcess()->GetID(); + EXPECT_NE(page_process_id, ChildProcessHost::kInvalidUniqueID); + ASSERT_EQ(GetRunningServiceWorkerCount(), 1u); + int worker_process_id = GetServiceWorkerProcessId(); + EXPECT_EQ(page_process_id, worker_process_id); +} + +// ContentBrowserClient that skips assigning a site URL for a given URL. +class DontAssignSiteContentBrowserClient : public TestContentBrowserClient { + public: + // Any visit to |url_to_skip| will not cause the site to be assigned to the + // SiteInstance. + explicit DontAssignSiteContentBrowserClient(const GURL& url_to_skip) + : url_to_skip_(url_to_skip) {} + + DontAssignSiteContentBrowserClient( + const DontAssignSiteContentBrowserClient&) = delete; + DontAssignSiteContentBrowserClient& operator=( + const DontAssignSiteContentBrowserClient&) = delete; + + bool ShouldAssignSiteForURL(const GURL& url) override { + return url == url_to_skip_; + } + + private: + GURL url_to_skip_; +}; + +// Tests that a service worker and navigation share the same process in the +// special case where the service worker starts before the navigation starts, +// and the navigation transitions out of a page with no site URL. This special +// case happens in real life when doing a search from the omnibox while on the +// Android native NTP page: the service worker starts first due to the +// navigation hint from the omnibox, and the native page has no site URL. See +// https://crbug.com/1012143. +IN_PROC_BROWSER_TEST_P( + ServiceWorkerProcessBrowserTest, + ServiceWorkerAndPageShareProcess_NavigateFromUnassignedSiteInstance) { + // Set up a page URL that will have no site URL. + GURL empty_site = embedded_test_server()->GetURL("a.com", "/title1.html"); + DontAssignSiteContentBrowserClient content_browser_client(empty_site); + ContentBrowserClient* old_client = + SetBrowserClientForTesting(&content_browser_client); + + // Register the service worker. + RegisterServiceWorker(); + + // Navigate to the empty site instance page. Subsequent navigations from + // this page will prefer to use the same process by default. + ASSERT_TRUE(NavigateToURL(shell(), empty_site)); + + // Start the service worker. It will start in a new process. + base::RunLoop loop; + GURL scope = embedded_test_server()->GetURL("/service_worker/"); + wrapper()->StartWorkerForScope( + scope, + base::BindLambdaForTesting([&loop](int64_t version_id, int process_id, + int thread_id) { loop.Quit(); }), + base::BindLambdaForTesting([&loop]() { + ASSERT_FALSE(true) << "start worker failed"; + loop.Quit(); + })); + loop.Run(); + + // Navigate to a page in the service worker's scope. + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("/service_worker/empty.html"))); + + // The page and service worker should be in the same process. + ASSERT_EQ(GetRunningServiceWorkerCount(), 1u); + int page_process_id = current_frame_host()->GetProcess()->GetID(); + EXPECT_NE(page_process_id, ChildProcessHost::kInvalidUniqueID); + EXPECT_EQ(page_process_id, GetServiceWorkerProcessId()); + + SetBrowserClientForTesting(old_client); +} + +// Toggle Site Isolation. +INSTANTIATE_TEST_SUITE_P(, ServiceWorkerProcessBrowserTest, testing::Bool()); + +} // namespace content
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index fbec490b6..546acdf3 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -2555,17 +2555,15 @@ SurfaceHitTestTestHelper(shell(), embedded_test_server()); } -// TODO(crbug/1014602): NestedSurfaceHitTestTest is flaky. - // Test that mouse events are being routed to the correct RenderWidgetHostView // when there are nested out-of-process iframes. IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, - DISABLED_NestedSurfaceHitTestTest) { + NestedSurfaceHitTestTest) { NestedSurfaceHitTestTestHelper(shell(), embedded_test_server()); } IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest, - DISABLED_NestedSurfaceHitTestTest) { + NestedSurfaceHitTestTest) { NestedSurfaceHitTestTestHelper(shell(), embedded_test_server()); } @@ -6282,7 +6280,7 @@ } IN_PROC_BROWSER_TEST_P(SitePerProcessNonIntegerScaleFactorHitTestBrowserTest, - DISABLED_NestedSurfaceHitTestTest) { + NestedSurfaceHitTestTest) { NestedSurfaceHitTestTestHelper(shell(), embedded_test_server()); }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 21e4fc1..a615d6200 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -689,7 +689,8 @@ // destroyed. RenderFrameHostManager* root = GetRenderManager(); - GetController().GetBackForwardCache().Flush(); + GetController().GetBackForwardCache().Shutdown(); + root->current_frame_host()->SetRenderFrameCreated(false); root->current_frame_host()->ResetNavigationRequests();
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index c59aeab..7662f7d 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -554,8 +554,8 @@ } namespace { -// A factory for creating DedicatedWorkerHosts. Its lifetime is managed by -// the renderer over mojo via a StrongBinding. This lives on the UI thread. +// A factory for creating DedicatedWorkerHosts. Its lifetime is managed by the +// renderer over mojo via SelfOwnedReceiver. It lives on the UI thread. class DedicatedWorkerHostFactoryImpl final : public blink::mojom::DedicatedWorkerHostFactory { public:
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h index e2bbb05..cbda5d5 100644 --- a/content/public/browser/navigation_handle.h +++ b/content/public/browser/navigation_handle.h
@@ -17,6 +17,7 @@ #include "net/base/auth.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/http/http_response_info.h" #include "services/network/public/cpp/resource_request_body.h" #include "ui/base/page_transition_types.h" @@ -284,6 +285,12 @@ virtual const base::Optional<net::AuthChallengeInfo>& GetAuthChallengeInfo() = 0; + // Gets the NetworkIsolationKey associated with the navigation. Updated as + // redirects are followed. When one of the origins used to construct the + // NetworkIsolationKey is opaque, the returned NetworkIsolationKey will not be + // consistent between calls. + virtual net::NetworkIsolationKey GetNetworkIsolationKey() = 0; + // Returns the ID of the URLRequest associated with this navigation. Can only // be called from NavigationThrottle::WillProcessResponse and // WebContentsObserver::ReadyToCommitNavigation.
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h index a82248cd..c69667c5 100644 --- a/content/public/browser/render_process_host.h +++ b/content/public/browser/render_process_host.h
@@ -360,6 +360,7 @@ // 4. Possibly more stpes, depending on the ChildThreadImpl subclass. virtual void BindReceiver(mojo::GenericPendingReceiver receiver) = 0; + // Can only be called when IsInitializedAndNotDead() is true. virtual const service_manager::Identity& GetChildIdentity() = 0; // Extracts any persistent-memory-allocator used for renderer metrics.
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h index 31274f6..9ce6c85 100644 --- a/content/public/test/mock_navigation_handle.h +++ b/content/public/test/mock_navigation_handle.h
@@ -11,6 +11,7 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "net/base/ip_endpoint.h" +#include "net/base/network_isolation_key.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/mojom/referrer.mojom.h" #include "url/gurl.h" @@ -89,6 +90,7 @@ override { return auth_challenge_info_; } + MOCK_METHOD0(GetNetworkIsolationKey, net::NetworkIsolationKey()); MOCK_METHOD0(GetGlobalRequestID, const GlobalRequestID&()); MOCK_METHOD0(IsDownload, bool()); bool IsFormSubmission() override { return is_form_submission_; }
diff --git a/content/renderer/media/webrtc/peer_connection_tracker.cc b/content/renderer/media/webrtc/peer_connection_tracker.cc index ccb773f..dcaa305 100644 --- a/content/renderer/media/webrtc/peer_connection_tracker.cc +++ b/content/renderer/media/webrtc/peer_connection_tracker.cc
@@ -13,12 +13,12 @@ #include <vector> #include "base/bind.h" +#include "base/lazy_instance.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" -#include "content/child/child_thread_impl.h" #include "content/common/media/peer_connection_tracker_messages.h" #include "content/renderer/media/webrtc/rtc_peer_connection_handler.h" #include "content/renderer/render_thread_impl.h" @@ -604,6 +604,24 @@ const scoped_refptr<base::SingleThreadTaskRunner> main_thread_; }; +struct PeerConnectionTrackerLazyInstanceTraits + : public base::internal::DestructorAtExitLazyInstanceTraits< + PeerConnectionTracker> { + static PeerConnectionTracker* New(void* instance) { + return new (instance) PeerConnectionTracker( + RenderThreadImpl::current()->main_thread_runner()); + } +}; + +base::LazyInstance<PeerConnectionTracker, + PeerConnectionTrackerLazyInstanceTraits> + g_peer_connection_tracker = LAZY_INSTANCE_INITIALIZER; + +// static +PeerConnectionTracker* PeerConnectionTracker::GetInstance() { + return &g_peer_connection_tracker.Get(); +} + PeerConnectionTracker::PeerConnectionTracker( scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) : next_local_id_(1),
diff --git a/content/renderer/media/webrtc/peer_connection_tracker.h b/content/renderer/media/webrtc/peer_connection_tracker.h index 3d81e5f1..29af0f4 100644 --- a/content/renderer/media/webrtc/peer_connection_tracker.h +++ b/content/renderer/media/webrtc/peer_connection_tracker.h
@@ -45,6 +45,8 @@ : public RenderThreadObserver, public base::SupportsWeakPtr<PeerConnectionTracker> { public: + static PeerConnectionTracker* GetInstance(); + explicit PeerConnectionTracker( scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner); PeerConnectionTracker(
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index 799dcc81..c8f2fcd1 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -1015,8 +1015,9 @@ CHECK(!initialize_called_); initialize_called_ = true; - peer_connection_tracker_ = - RenderThreadImpl::current()->peer_connection_tracker()->AsWeakPtr(); + // TODO(crbug.com/787254): Evaluate the need for passing weak ptr since + // PeerConnectionTracker is now leaky with base::LazyInstance. + peer_connection_tracker_ = PeerConnectionTracker::GetInstance()->AsWeakPtr(); configuration_ = server_configuration;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index aaf5a4487..a77b6dd 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -753,9 +753,7 @@ browser_plugin_manager_.reset(new BrowserPluginManager()); AddObserver(browser_plugin_manager_.get()); - peer_connection_tracker_.reset( - new PeerConnectionTracker(main_thread_runner())); - AddObserver(peer_connection_tracker_.get()); + AddObserver(PeerConnectionTracker::GetInstance()); unfreezable_message_filter_ = new UnfreezableMessageFilter(this); AddFilter(unfreezable_message_filter_.get());
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 16def76..b9ad30f 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -103,7 +103,6 @@ class CategorizedWorkerPool; class GpuVideoAcceleratorFactoriesImpl; class LowMemoryModeController; -class PeerConnectionTracker; class RenderThreadObserver; class RendererBlinkPlatformImpl; class ResourceDispatcher; @@ -291,10 +290,6 @@ return browser_plugin_manager_.get(); } - PeerConnectionTracker* peer_connection_tracker() { - return peer_connection_tracker_.get(); - } - blink::WebVideoCaptureImplManager* video_capture_impl_manager() const { return vc_manager_.get(); } @@ -553,10 +548,6 @@ std::unique_ptr<BrowserPluginManager> browser_plugin_manager_; - // This is used to communicate to the browser process the status - // of all the peer connections created in the renderer. - std::unique_ptr<PeerConnectionTracker> peer_connection_tracker_; - // Filter out unfreezable messages and pass it to unfreezable task runners. scoped_refptr<UnfreezableMessageFilter> unfreezable_message_filter_;
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 541268de..0721224 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -699,8 +699,7 @@ void RendererBlinkPlatformImpl::TrackGetUserMedia( const blink::WebUserMediaRequest& web_request) { - RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia( - web_request); + PeerConnectionTracker::GetInstance()->TrackGetUserMedia(web_request); } bool RendererBlinkPlatformImpl::IsWebRtcHWH264DecodingEnabled(
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 1d7fb6a..644231b1 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1031,6 +1031,7 @@ "../browser/service_worker/service_worker_clients_api_browsertest.cc", "../browser/service_worker/service_worker_file_upload_browsertest.cc", "../browser/service_worker/service_worker_no_best_effort_tasks_browsertest.cc", + "../browser/service_worker/service_worker_process_browsertest.cc", "../browser/session_history_browsertest.cc", "../browser/shape_detection/shape_detection_browsertest.cc", "../browser/site_per_process_browsertest.cc",
diff --git a/docs/adding_to_third_party.md b/docs/adding_to_third_party.md index 26b1c9fe..06be7f9 100644 --- a/docs/adding_to_third_party.md +++ b/docs/adding_to_third_party.md
@@ -18,6 +18,15 @@ other directory with third_party in the name it's okay to put new things there. +## Before you start + +To make sure the inclusion of a new third_party project makes sense for the +Chromium project, you should first obtain Chrome Eng Review approval. +Googlers should see go/chrome-eng-review and review existing topics in +g/chrome-eng-review. Please include information about the additional checkout +size, build times, and binary sizes. Please also make sure that the motivation +for your project is clear, e.g., a design doc has been circulated. + ## Get the code There are two common ways to depend on third-party code: you can reference a @@ -27,6 +36,14 @@ of the repo or don't need to pick up every single change. And, of course, if the code you need isn't in a Git repo, you have to do the latter. +### Node packages + +To include a Node package, add the dependency to the +[Node package.json](../third_party/node/package.json). Make sure to update +the corresponding [`npm_exclude.txt`](../third_party/node/npm_exclude.txt) +and [`npm_include.txt`](../third_party/node/npm_include.txt) to make the code +available during checkout. + ### Pulling the code via DEPS If the code is in a Git repo that you want to mirror, please file an [infra git @@ -126,10 +143,6 @@ Non-Googlers can email one of the people in [//third_party/OWNERS](../third_party/OWNERS) for help. -* Get Chrome Eng Review approval. Googlers should see - go/chrome-eng-review. Please include information about the additional - checkout size, build times, and binary sizes. Please also make sure that the - motivation for your project is clear, e.g., a design doc has been circulated. * Get security@chromium.org approval. Email the list with relevant details and a link to the CL. Third party code is a hot spot for security vulnerabilities. When adding a new package that could potentially carry security risk, make
diff --git a/docs/process/merge_request.md b/docs/process/merge_request.md index 9ee67df5c..0905103 100644 --- a/docs/process/merge_request.md +++ b/docs/process/merge_request.md
@@ -86,6 +86,10 @@ Security bugs should be consulted with [chrome-security@](chrome-security@google.com) to determine criticality. +If it is unclear whether the severity of the issue meets the bar for merging +consult with the [TPM](https://chromiumdash.appspot.com/schedule) and your +manager. + This table below provides key dates and phases as an example, for M61 release. Key Event | Date
diff --git a/extensions/browser/api/automation_internal/automation_internal_api.cc b/extensions/browser/api/automation_internal/automation_internal_api.cc index f6de53d..5a60dae2 100644 --- a/extensions/browser/api/automation_internal/automation_internal_api.cc +++ b/extensions/browser/api/automation_internal/automation_internal_api.cc
@@ -391,6 +391,10 @@ break; case api::automation::ACTION_TYPE_SCROLLTOMAKEVISIBLE: action->action = ax::mojom::Action::kScrollToMakeVisible; + action->horizontal_scroll_alignment = + ax::mojom::ScrollAlignment::kScrollAlignmentCenter; + action->vertical_scroll_alignment = + ax::mojom::ScrollAlignment::kScrollAlignmentCenter; break; case api::automation::ACTION_TYPE_SCROLLBACKWARD: action->action = ax::mojom::Action::kScrollBackward;
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index a149629c..5a9afb9 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1457,6 +1457,7 @@ AUTOTESTPRIVATE_GETAPPWINDOWLIST = 1394, AUTOTESTPRIVATE_SETAPPWINDOWSTATE = 1395, AUTOTESTPRIVATE_CLOSEAPPWINDOW = 1396, + AUTOTESTPRIVATE_REFRESHENTERPRISEPOLICIES = 1397, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index 39323b1e..46bf69e 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -133,6 +133,7 @@ "main_application_delegate_testing.h", "main_controller.h", "main_controller.mm", + "main_controller_guts.h", "main_controller_private.h", "memory_monitor.h", "memory_monitor.mm",
diff --git a/ios/chrome/app/main_controller.h b/ios/chrome/app/main_controller.h index d300dc6..f1194444 100644 --- a/ios/chrome/app/main_controller.h +++ b/ios/chrome/app/main_controller.h
@@ -12,6 +12,7 @@ #import "ios/chrome/app/application_delegate/startup_information.h" #import "ios/chrome/app/application_delegate/tab_opening.h" #import "ios/chrome/app/application_delegate/tab_switching.h" +#import "ios/chrome/app/main_controller_guts.h" #import "ios/chrome/browser/ui/commands/application_commands.h" @class AppState; @@ -23,12 +24,13 @@ // // By design, it has no public API of its own. Anything interacting with // MainController should be doing so through a specific protocol. -@interface MainController : NSObject<ApplicationCommands, - AppNavigation, - BrowserLauncher, - StartupInformation, - TabOpening, - TabSwitching> +@interface MainController : NSObject <ApplicationCommands, + AppNavigation, + BrowserLauncher, + MainControllerGuts, + StartupInformation, + TabOpening, + TabSwitching> // The application window. @property(nonatomic, strong) UIWindow* window;
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index c3f3ceaf..ad4a3c3 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -330,9 +330,6 @@ // The object that drives the Chrome startup/shutdown logic. std::unique_ptr<IOSChromeMain> _chromeMain; - // The ChromeBrowserState associated with the main (non-OTR) browsing mode. - ios::ChromeBrowserState* _mainBrowserState; // Weak. - // Wrangler to handle BVC and tab model creation, access, and related logic. // Implements faetures exposed from this object through the // BrowserViewInformation protocol. @@ -372,18 +369,6 @@ // in a modal dialog. BOOL _isPresentingFirstRunUI; - // The tab switcher command and the voice search commands can be sent by views - // that reside in a different UIWindow leading to the fact that the exclusive - // touch property will be ineffective and a command for processing both - // commands may be sent in the same run of the runloop leading to - // inconsistencies. Those two boolean indicate if one of those commands have - // been processed in the last 200ms in order to only allow processing one at - // a time. - // TODO(crbug.com/560296): Provide a general solution for handling mutually - // exclusive chrome commands sent at nearly the same time. - BOOL _isProcessingTabSwitcherCommand; - BOOL _isProcessingVoiceSearchCommand; - // Bridge to listen to pref changes. std::unique_ptr<PrefObserverBridge> _localStatePrefObserverBridge; @@ -406,23 +391,20 @@ // Cached launchOptions from -didFinishLaunchingWithOptions. NSDictionary* _launchOptions; - // Coordinator for displaying history. - HistoryCoordinator* _historyCoordinator; - // Variable backing metricsMediator property. __weak MetricsMediator* _metricsMediator; // Hander for the startup tasks, deferred or not. StartupTasks* _startupTasks; - // The application level component for url loading. Is passed down to - // browser state level UrlLoadingService instances. - AppUrlLoadingService* _appURLLoadingService; - // If the animations were disabled. BOOL _animationDisabled; } +// The ChromeBrowserState associated with the main (non-OTR) browsing mode. +@property(nonatomic, assign) + ios::ChromeBrowserState* mainBrowserState; // Weak. + // The main coordinator, lazily created the first time it is accessed. Manages // the main view controller. This property should not be accessed before the // browser has started up to the FOREGROUND stage. @@ -434,12 +416,6 @@ @property(nonatomic, readwrite) NTPTabOpeningPostOpeningAction NTPActionAfterTabSwitcherDismissal; -// The SigninInteractionCoordinator to present Sign In UI. It is created the -// first time Sign In UI is needed to be presented and should not be destroyed -// while the UI is presented. -@property(nonatomic, strong) - SigninInteractionCoordinator* signinInteractionCoordinator; - // Returns YES if the settings are presented, either from // _settingsNavigationController or from SigninInteractionCoordinator. @property(nonatomic, assign, readonly, getter=isSettingsViewPresented) @@ -573,10 +549,15 @@ @end @implementation MainController +// Defined by MainControllerGuts. +@synthesize historyCoordinator; +@synthesize settingsNavigationController; +@synthesize appURLLoadingService; +@synthesize isProcessingTabSwitcherCommand; +@synthesize isProcessingVoiceSearchCommand; +@synthesize signinInteractionCoordinator; // Defined by public protocols. -// - AppNavigation -@synthesize settingsNavigationController = _settingsNavigationController; // - BrowserLauncher @synthesize launchOptions = _launchOptions; @synthesize browserInitializationStage = _browserInitializationStage; @@ -589,7 +570,6 @@ @synthesize mainCoordinator = _mainCoordinator; @synthesize NTPActionAfterTabSwitcherDismissal = _NTPActionAfterTabSwitcherDismissal; -@synthesize signinInteractionCoordinator = _signinInteractionCoordinator; #pragma mark - Application lifecycle @@ -721,29 +701,29 @@ [_restoreHelper moveAsideSessionInformation]; } - _appURLLoadingService = new AppUrlLoadingService(); - _appURLLoadingService->SetDelegate(self); + self.appURLLoadingService = new AppUrlLoadingService(); + self.appURLLoadingService->SetDelegate(self); // Initialize and set the main browser state. [self initializeBrowserState:chromeBrowserState]; - _mainBrowserState = chromeBrowserState; + self.mainBrowserState = chromeBrowserState; [_browserViewWrangler shutdown]; - _browserViewWrangler = - [[BrowserViewWrangler alloc] initWithBrowserState:_mainBrowserState - webStateListObserver:self - applicationCommandEndpoint:self - appURLLoadingService:_appURLLoadingService - storageSwitcher:self]; + _browserViewWrangler = [[BrowserViewWrangler alloc] + initWithBrowserState:self.mainBrowserState + webStateListObserver:self + applicationCommandEndpoint:self + appURLLoadingService:self.appURLLoadingService + storageSwitcher:self]; // Force an obvious initialization of the AuthenticationService. This must // be done before creation of the UI to ensure the service is initialised // before use (it is a security issue, so accessing the service CHECK if // this is not the case). - DCHECK(_mainBrowserState); + DCHECK(self.mainBrowserState); AuthenticationServiceFactory::CreateAndInitializeForBrowserState( - _mainBrowserState, + self.mainBrowserState, std::make_unique<MainControllerAuthenticationServiceDelegate>( - _mainBrowserState, self)); + self.mainBrowserState, self)); // Send "Chrome Opened" event to the feature_engagement::Tracker on cold // start. @@ -757,10 +737,10 @@ [_browserViewWrangler createMainBrowser]; _spotlightManager = - [SpotlightManager spotlightManagerWithBrowserState:_mainBrowserState]; + [SpotlightManager spotlightManagerWithBrowserState:self.mainBrowserState]; ShareExtensionService* service = - ShareExtensionServiceFactory::GetForBrowserState(_mainBrowserState); + ShareExtensionServiceFactory::GetForBrowserState(self.mainBrowserState); service->Initialize(); // Before bringing up the UI, make sure the launch mode is correct, and @@ -791,9 +771,9 @@ interfaceProvider:self.interfaceProvider]; if (self.isColdStart) { [ContentSuggestionsSchedulerNotifications - notifyColdStart:_mainBrowserState]; + notifyColdStart:self.mainBrowserState]; [ContentSuggestionsSchedulerNotifications - notifyForeground:_mainBrowserState]; + notifyForeground:self.mainBrowserState]; } ios::GetChromeBrowserProvider()->GetOverridesProvider()->InstallOverrides(); @@ -868,9 +848,9 @@ } - (void)clearIOSSpecificIncognitoData { - DCHECK(_mainBrowserState->HasOffTheRecordChromeBrowserState()); + DCHECK(self.mainBrowserState->HasOffTheRecordChromeBrowserState()); ios::ChromeBrowserState* otrBrowserState = - _mainBrowserState->GetOffTheRecordChromeBrowserState(); + self.mainBrowserState->GetOffTheRecordChromeBrowserState(); [self removeBrowsingDataForBrowserState:otrBrowserState timePeriod:browsing_data::TimePeriod::ALL_TIME removeMask:BrowsingDataRemoveMask::REMOVE_ALL @@ -988,8 +968,8 @@ _extensionSearchEngineDataUpdater = nullptr; - [_historyCoordinator stop]; - _historyCoordinator = nil; + [self.historyCoordinator stop]; + self.historyCoordinator = nil; ios::GetChromeBrowserProvider() ->GetMailtoHandlerProvider() @@ -1096,7 +1076,7 @@ // Track changes to default search engine. TemplateURLService* service = ios::TemplateURLServiceFactory::GetForBrowserState( - _mainBrowserState); + self.mainBrowserState); _extensionSearchEngineDataUpdater = std::make_unique<ExtensionSearchEngineDataUpdater>( service); @@ -1108,7 +1088,7 @@ enqueueBlockNamed:kSendInstallPingIfNecessary block:^{ auto URLLoaderFactory = - _mainBrowserState->GetSharedURLLoaderFactory(); + self.mainBrowserState->GetSharedURLLoaderFactory(); bool is_first_run = FirstRun::IsChromeFirstRun(); ios::GetChromeBrowserProvider() ->GetAppDistributionProvider() @@ -1168,10 +1148,10 @@ // ClearSessionCookies() is not synchronous. if (cookie_util::ShouldClearSessionCookies()) { cookie_util::ClearSessionCookies( - _mainBrowserState->GetOriginalChromeBrowserState()); + self.mainBrowserState->GetOriginalChromeBrowserState()); if (![self.otrTabModel isEmpty]) { cookie_util::ClearSessionCookies( - _mainBrowserState->GetOffTheRecordChromeBrowserState()); + self.mainBrowserState->GetOffTheRecordChromeBrowserState()); } } @@ -1201,12 +1181,12 @@ enqueueBlockNamed:kMailtoHandlingInitialization block:^{ __strong __typeof(weakSelf) strongSelf = weakSelf; - if (!strongSelf || !strongSelf->_mainBrowserState) { + if (!strongSelf || !strongSelf.mainBrowserState) { return; } ios::GetChromeBrowserProvider() ->GetMailtoHandlerProvider() - ->PrepareMailtoHandling(strongSelf->_mainBrowserState); + ->PrepareMailtoHandling(strongSelf.mainBrowserState); }]; } @@ -1276,7 +1256,8 @@ // Deferred tasks. [self schedulePrefObserverInitialization]; [self scheduleMemoryDebuggingTools]; - [StartupTasks scheduleDeferredBrowserStateInitialization:_mainBrowserState]; + [StartupTasks + scheduleDeferredBrowserStateInitialization:self.mainBrowserState]; [self scheduleAuthenticationServiceNotification]; [self sendQueuedFeedback]; [self scheduleSpotlightResync]; @@ -1294,7 +1275,7 @@ if (GetApplicationContext()->WasLastShutdownClean()) { // Delay the cleanup of the unreferenced files to not impact startup // performance. - ExternalFileRemoverFactory::GetForBrowserState(_mainBrowserState) + ExternalFileRemoverFactory::GetForBrowserState(self.mainBrowserState) ->RemoveAfterDelay( base::TimeDelta::FromSeconds(kExternalFilesCleanupDelaySeconds), base::OnceClosure()); @@ -1361,7 +1342,7 @@ } - (void)createInitialUI:(ApplicationMode)launchMode { - DCHECK(_mainBrowserState); + DCHECK(self.mainBrowserState); // In order to correctly set the mode switch icon, we need to know how many // tabs are in the other tab model. That means loading both models. They @@ -1395,8 +1376,8 @@ ios::ChromeBrowserState* browserState = (launchMode == ApplicationMode::INCOGNITO) - ? _mainBrowserState->GetOffTheRecordChromeBrowserState() - : _mainBrowserState; + ? self.mainBrowserState->GetOffTheRecordChromeBrowserState() + : self.mainBrowserState; [self changeStorageFromBrowserState:nullptr toBrowserState:browserState]; TabModel* tabModel; @@ -1444,7 +1425,7 @@ WelcomeToChromeViewController* welcomeToChrome = [[WelcomeToChromeViewController alloc] - initWithBrowserState:_mainBrowserState + initWithBrowserState:self.mainBrowserState tabModel:self.mainTabModel presenter:self.mainBVC dispatcher:self.mainBVC.dispatcher]; @@ -1486,9 +1467,9 @@ // Show the sign-in promo if needed if ([SigninPromoViewController - shouldBePresentedForBrowserState:_mainBrowserState]) { + shouldBePresentedForBrowserState:self.mainBrowserState]) { UIViewController* promoController = [[SigninPromoViewController alloc] - initWithBrowserState:_mainBrowserState + initWithBrowserState:self.mainBrowserState dispatcher:self.mainBVC.dispatcher]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, @@ -1533,14 +1514,14 @@ } - (void)showHistory { - _historyCoordinator = - [[HistoryCoordinator alloc] initWithBaseViewController:self.currentBVC - browserState:_mainBrowserState]; - _historyCoordinator.loadStrategy = [self currentPageIsIncognito] - ? UrlLoadStrategy::ALWAYS_IN_INCOGNITO - : UrlLoadStrategy::NORMAL; - _historyCoordinator.dispatcher = self.mainBVC.dispatcher; - [_historyCoordinator start]; + self.historyCoordinator = [[HistoryCoordinator alloc] + initWithBaseViewController:self.currentBVC + browserState:self.mainBrowserState]; + self.historyCoordinator.loadStrategy = + [self currentPageIsIncognito] ? UrlLoadStrategy::ALWAYS_IN_INCOGNITO + : UrlLoadStrategy::NORMAL; + self.historyCoordinator.dispatcher = self.mainBVC.dispatcher; + [self.historyCoordinator start]; } - (void)closeSettingsUIAndOpenURL:(OpenNewTabCommand*)command { @@ -1582,14 +1563,14 @@ - (void)displayTabSwitcher { DCHECK(!_tabSwitcherIsActive); - if (!_isProcessingVoiceSearchCommand) { + if (!self.isProcessingVoiceSearchCommand) { [self.currentBVC userEnteredTabSwitcher]; [self showTabSwitcher]; - _isProcessingTabSwitcherCommand = YES; + self.isProcessingTabSwitcherCommand = YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kExpectedTransitionDurationInNanoSeconds), dispatch_get_main_queue(), ^{ - _isProcessingTabSwitcherCommand = NO; + self.isProcessingTabSwitcherCommand = NO; }); } } @@ -1642,7 +1623,7 @@ params.from_chrome = command.fromChrome; params.user_initiated = command.userInitiated; params.should_focus_omnibox = command.shouldFocusOmnibox; - _appURLLoadingService->LoadUrlInNewTab(params); + self.appURLLoadingService->LoadUrlInNewTab(params); } // TODO(crbug.com/779791) : Do not pass |baseViewController| through dispatcher. @@ -1650,7 +1631,7 @@ baseViewController:(UIViewController*)baseViewController { if (!self.signinInteractionCoordinator) { self.signinInteractionCoordinator = [[SigninInteractionCoordinator alloc] - initWithBrowserState:_mainBrowserState + initWithBrowserState:self.mainBrowserState dispatcher:self.mainBVC.dispatcher]; } @@ -1675,7 +1656,7 @@ - (void)showAdvancedSigninSettingsFromViewController: (UIViewController*)baseViewController { self.signinInteractionCoordinator = [[SigninInteractionCoordinator alloc] - initWithBrowserState:_mainBrowserState + initWithBrowserState:self.mainBrowserState dispatcher:self.mainBVC.dispatcher]; [self.signinInteractionCoordinator showAdvancedSigninSettingsWithPresentingViewController: @@ -1686,7 +1667,7 @@ - (void)showAddAccountFromViewController:(UIViewController*)baseViewController { if (!self.signinInteractionCoordinator) { self.signinInteractionCoordinator = [[SigninInteractionCoordinator alloc] - initWithBrowserState:_mainBrowserState + initWithBrowserState:self.mainBrowserState dispatcher:self.mainBVC.dispatcher]; } @@ -1959,7 +1940,7 @@ // browser state. breakpad_helper::SetDestroyingAndRebuildingIncognitoBrowserState( /*in_progress=*/true); - DCHECK(_mainBrowserState->HasOffTheRecordChromeBrowserState()); + DCHECK(self.mainBrowserState->HasOffTheRecordChromeBrowserState()); [self clearIOSSpecificIncognitoData]; // OffTheRecordProfileIOData cannot be deleted before all the requests are @@ -2004,13 +1985,13 @@ #pragma mark - Mode Switching - (void)startVoiceSearch { - if (!_isProcessingTabSwitcherCommand) { + if (!self.isProcessingTabSwitcherCommand) { [self startVoiceSearchInCurrentBVC]; - _isProcessingVoiceSearchCommand = YES; + self.isProcessingVoiceSearchCommand = YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kExpectedTransitionDurationInNanoSeconds), dispatch_get_main_queue(), ^{ - _isProcessingVoiceSearchCommand = NO; + self.isProcessingVoiceSearchCommand = NO; }); } } @@ -2633,7 +2614,7 @@ payments::IOSPaymentInstrumentLauncher* paymentAppLauncher = payments::IOSPaymentInstrumentLauncherFactory::GetInstance() - ->GetForBrowserState(_mainBrowserState); + ->GetForBrowserState(self.mainBrowserState); if (!paymentAppLauncher->delegate()) return NO; @@ -2710,6 +2691,12 @@ return username.empty() ? nil : base::SysUTF8ToNSString(username); } +#pragma mark - MainControllerGuts + +- (id<TabSwitcher>)tabSwitcher { + return _tabSwitcher; +} + @end #pragma mark - TestingOnly @@ -2720,10 +2707,6 @@ return [_browserViewWrangler deviceSharingManager]; } -- (id<TabSwitcher>)tabSwitcher { - return _tabSwitcher; -} - - (void)setTabSwitcher:(id<TabSwitcher>)switcher { _tabSwitcher = switcher; }
diff --git a/ios/chrome/app/main_controller_guts.h b/ios/chrome/app/main_controller_guts.h new file mode 100644 index 0000000..67754969 --- /dev/null +++ b/ios/chrome/app/main_controller_guts.h
@@ -0,0 +1,79 @@ +// Copyright 2019 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 IOS_CHROME_APP_MAIN_CONTROLLER_GUTS_H_ +#define IOS_CHROME_APP_MAIN_CONTROLLER_GUTS_H_ + +#import <UIKit/UIKit.h> + +#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" +#import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h" + +@class HistoryCoordinator; +@class SigninInteractionCoordinator; +@class TabGridCoordinator; +@protocol BrowserInterfaceProvider; +@protocol TabSwitcher; +class AppUrlLoadingService; + +// TODO(crbug.com/1012697): Remove this protocol when SceneController is +// operational. Move the private internals back into MainController, and pass +// ownership of Scene-related objects to SceneController. +@protocol MainControllerGuts <SettingsNavigationControllerDelegate, + UserFeedbackDataSource> + +// Coordinator for displaying history. +@property(nonatomic, strong) HistoryCoordinator* historyCoordinator; +@property(nonatomic, strong) + SettingsNavigationController* settingsNavigationController; + +// The application level component for url loading. Is passed down to +// browser state level UrlLoadingService instances. +@property(nonatomic, assign) AppUrlLoadingService* appURLLoadingService; + +// The tab switcher command and the voice search commands can be sent by views +// that reside in a different UIWindow leading to the fact that the exclusive +// touch property will be ineffective and a command for processing both +// commands may be sent in the same run of the runloop leading to +// inconsistencies. Those two boolean indicate if one of those commands have +// been processed in the last 200ms in order to only allow processing one at +// a time. +// TODO(crbug.com/560296): Provide a general solution for handling mutually +// exclusive chrome commands sent at nearly the same time. +@property(nonatomic, assign) BOOL isProcessingTabSwitcherCommand; +@property(nonatomic, assign) BOOL isProcessingVoiceSearchCommand; +// The SigninInteractionCoordinator to present Sign In UI. It is created the +// first time Sign In UI is needed to be presented and should not be destroyed +// while the UI is presented. +@property(nonatomic, strong) + SigninInteractionCoordinator* signinInteractionCoordinator; + +- (BOOL)isTabSwitcherActive; + +- (id<TabSwitcher>)tabSwitcher; +- (ios::ChromeBrowserState*)mainBrowserState; +- (ios::ChromeBrowserState*)currentBrowserState; +- (BrowserViewController*)currentBVC; +- (BrowserViewController*)mainBVC; +- (BrowserViewController*)otrBVC; +- (TabGridCoordinator*)mainCoordinator; +- (id<BrowserInterfaceProvider>)interfaceProvider; +- (void)startVoiceSearchInCurrentBVC; + +- (void)dismissModalDialogsWithCompletion:(ProceduralBlock)completion + dismissOmnibox:(BOOL)dismissOmnibox; +- (void)closeSettingsAnimated:(BOOL)animated + completion:(ProceduralBlock)completion; + +- (void)dismissModalsAndOpenSelectedTabInMode: + (ApplicationModeForTabOpening)targetMode + withUrlLoadParams: + (const UrlLoadParams&)urlLoadParams + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion; +- (void)showTabSwitcher; + +@end + +#endif // IOS_CHROME_APP_MAIN_CONTROLLER_GUTS_H_
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h index 33b9bb7..f14dc1b 100644 --- a/ios/chrome/browser/signin/authentication_service.h +++ b/ios/chrome/browser/signin/authentication_service.h
@@ -66,7 +66,7 @@ // they were stored in the browser state prefs. This storing happens every // time the accounts change in foreground. // This reloads the cached accounts if the information might be stale. - virtual bool HaveAccountsChanged() const; + virtual bool HaveAccountsChangedWhileInBackground() const; // ChromeIdentity management @@ -126,14 +126,23 @@ // ids. void MigrateAccountsStoredInPrefsIfNeeded(); - // Stores the token service accounts in the browser state prefs. - void StoreAccountsInPrefs(); + // Saves the last known list of accounts from the token service when + // the app is in foreground. This can be used when app comes back from + // background to detect if any changes occurred to the list. Must only + // be called when the application is in foreground. + // See HaveAccountsChangesWhileInBackground(). + void StoreKnownAccountsWhileInForeground(); - // Gets the accounts previously stored in the browser state prefs. - std::vector<std::string> GetAccountsInPrefs(); + // Gets the accounts previously stored as the foreground accounts in the + // browser state prefs. + // Returns the list of previously stored known accounts. This list + // is only updated when the app is in foreground and used to detect + // if any change occurred while the app was in background. + // See HaveAccountsChangesWhileInBackground(). + std::vector<std::string> GetLastKnownAccountsFromForeground(); - // Returns the cached MDM infos associated with |identity|. If the cache is - // stale for |identity|, the entry might be removed. + // Returns the cached MDM infos associated with |identity|. If the cache + // is stale for |identity|, the entry might be removed. NSDictionary* GetCachedMDMInfo(ChromeIdentity* identity) const; // Handles an MDM notification |user_info| associated with |identity|. @@ -147,7 +156,7 @@ // // |in_foreground| indicates whether the application was in foreground when // the identity list change notification was received. - void HandleIdentityListChanged(bool in_foreground); + void HandleIdentityListChanged(); // Verifies that the authenticated user is still associated with a valid // ChromeIdentity. This method must only be called when the user is @@ -177,6 +186,9 @@ // or when the application is entering foregorund. void UpdateHaveAccountsChangedWhileInBackground(); + // Returns whether the application is currently in the foreground or not. + bool InForeground() const; + // signin::IdentityManager::Observer implementation. void OnEndBatchOfRefreshTokenStateChanges() override; @@ -203,7 +215,7 @@ // Whether the accounts have changed while the AuthenticationService was in // background. When the AuthenticationService is in background, this value // cannot be trusted. - bool have_accounts_changed_ = false; + bool have_accounts_changed_while_in_background_ = false; // Whether the AuthenticationService is currently reloading credentials, used // to avoid an infinite reloading loop.
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm index f2837852..2fa22201 100644 --- a/ios/chrome/browser/signin/authentication_service.mm +++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -123,7 +123,7 @@ } void AuthenticationService::OnApplicationWillEnterForeground() { - if (identity_manager_observer_.IsObservingSources()) + if (InForeground()) return; identity_manager_observer_.Add(identity_manager_); @@ -133,7 +133,7 @@ // changed (both are done by |UpdateHaveAccountsChangedWhileInBackground|). // After that, save the current list of accounts. UpdateHaveAccountsChangedWhileInBackground(); - StoreAccountsInPrefs(); + StoreKnownAccountsWhileInForeground(); if (IsAuthenticated()) { bool sync_enabled = sync_setup_service_->IsSyncEnabled(); @@ -166,13 +166,23 @@ } void AuthenticationService::OnApplicationDidEnterBackground() { - if (!identity_manager_observer_.IsObservingSources()) + if (!InForeground()) return; // Stop observing |identity_manager_| when in the background. Note that // this allows checking whether the app is in background without having a // separate bool by using identity_manager_observer_.IsObservingSources(). identity_manager_observer_.Remove(identity_manager_); + + // Reset the state |have_accounts_changed_while_in_background_| as the + // application just entered background. + have_accounts_changed_while_in_background_ = false; +} + +bool AuthenticationService::InForeground() const { + // The application is in foreground when |identity_manager_observer_| is + // observing sources. + return identity_manager_observer_.IsObservingSources(); } void AuthenticationService::SetPromptForSignIn() { @@ -191,8 +201,9 @@ // Load accounts from preference before synchronizing the accounts with // the system, otherwiser we would never detect any changes to the list // of accounts. - std::vector<std::string> old_accounts = GetAccountsInPrefs(); - std::sort(old_accounts.begin(), old_accounts.end()); + std::vector<std::string> last_foreground_accounts = + GetLastKnownAccountsFromForeground(); + std::sort(last_foreground_accounts.begin(), last_foreground_accounts.end()); // Reload credentials to ensure the accounts from the token service are // up-to-date. @@ -201,18 +212,19 @@ // must be set to true. ReloadCredentialsFromIdentities(/*should_prompt=*/true); - std::vector<CoreAccountInfo> new_accounts_info = + std::vector<CoreAccountInfo> current_accounts_info = identity_manager_->GetAccountsWithRefreshTokens(); - std::vector<std::string> new_accounts; - for (const CoreAccountInfo& account_info : new_accounts_info) - new_accounts.push_back(account_info.account_id); - std::sort(new_accounts.begin(), new_accounts.end()); + std::vector<std::string> current_accounts; + for (const CoreAccountInfo& account_info : current_accounts_info) + current_accounts.push_back(account_info.account_id); + std::sort(current_accounts.begin(), current_accounts.end()); - have_accounts_changed_ = old_accounts != new_accounts; + have_accounts_changed_while_in_background_ = + last_foreground_accounts != current_accounts; } -bool AuthenticationService::HaveAccountsChanged() const { - return have_accounts_changed_; +bool AuthenticationService::HaveAccountsChangedWhileInBackground() const { + return have_accounts_changed_while_in_background_; } void AuthenticationService::MigrateAccountsStoredInPrefsIfNeeded() { @@ -227,7 +239,7 @@ return; } - std::vector<std::string> account_ids = GetAccountsInPrefs(); + std::vector<std::string> account_ids = GetLastKnownAccountsFromForeground(); std::vector<base::Value> accounts_pref_value; for (const std::string& account_id : account_ids) { if (identity_manager_->HasAccountWithRefreshToken(account_id)) { @@ -235,8 +247,8 @@ } else { // The account for |email| was removed since the last application cold // start. Insert |kFakeAccountIdForRemovedAccount| to ensure - // |have_accounts_changed_| will be set to true and the removal won't be - // silently ignored. + // |have_accounts_changed_while_in_background_| will be set to true and + // the removal won't be silently ignored. accounts_pref_value.emplace_back(kFakeAccountIdForRemovedAccount); } } @@ -245,7 +257,8 @@ pref_service_->SetBoolean(prefs::kSigninLastAccountsMigrated, true); } -void AuthenticationService::StoreAccountsInPrefs() { +void AuthenticationService::StoreKnownAccountsWhileInForeground() { + DCHECK(InForeground()); std::vector<CoreAccountInfo> accounts( identity_manager_->GetAccountsWithRefreshTokens()); std::vector<base::Value> accounts_pref_value; @@ -255,7 +268,8 @@ base::Value(std::move(accounts_pref_value))); } -std::vector<std::string> AuthenticationService::GetAccountsInPrefs() { +std::vector<std::string> +AuthenticationService::GetLastKnownAccountsFromForeground() { const base::Value* accounts_pref = pref_service_->GetList(prefs::kSigninLastAccounts); @@ -418,7 +432,7 @@ // Accounts maybe have been excluded or included from the current browser // state, without any change to the identity list. // Store the current list of accounts to make sure it is up-to-date. - StoreAccountsInPrefs(); + StoreKnownAccountsWhileInForeground(); } void AuthenticationService::OnIdentityListChanged() { @@ -429,8 +443,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&AuthenticationService::HandleIdentityListChanged, - GetWeakPtr(), - identity_manager_observer_.IsObservingSources())); + GetWeakPtr())); } bool AuthenticationService::HandleMDMNotification(ChromeIdentity* identity, @@ -494,10 +507,10 @@ identity_service_observer_.RemoveAll(); } -void AuthenticationService::HandleIdentityListChanged(bool in_foreground) { +void AuthenticationService::HandleIdentityListChanged() { // Only notify the user about an identity change notification if the // application was in background. - if (in_foreground) { + if (InForeground()) { // Do not update the have accounts change state when in foreground. ReloadCredentialsFromIdentities(/*should_prompt=*/false); return;
diff --git a/ios/chrome/browser/signin/authentication_service_fake.h b/ios/chrome/browser/signin/authentication_service_fake.h index f6cf90e..0502c213 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.h +++ b/ios/chrome/browser/signin/authentication_service_fake.h
@@ -31,9 +31,9 @@ void SignOut(signin_metrics::ProfileSignout signout_source, ProceduralBlock completion) override; - void SetHaveAccountsChanged(bool changed); + void SetHaveAccountsChangedWhileInBackground(bool changed); - bool HaveAccountsChanged() const override; + bool HaveAccountsChangedWhileInBackground() const override; bool IsAuthenticated() const override; @@ -46,7 +46,7 @@ syncer::SyncService* sync_service); __strong ChromeIdentity* authenticated_identity_; - bool have_accounts_changed_; + bool have_accounts_changed_while_in_background_; }; #endif // IOS_CHROME_BROWSER_SIGNIN_AUTHENTICATION_SERVICE_FAKE_H_
diff --git a/ios/chrome/browser/signin/authentication_service_fake.mm b/ios/chrome/browser/signin/authentication_service_fake.mm index cdf7324..09292fce 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.mm +++ b/ios/chrome/browser/signin/authentication_service_fake.mm
@@ -29,7 +29,7 @@ sync_setup_service, identity_manager, sync_service), - have_accounts_changed_(false) {} + have_accounts_changed_while_in_background_(false) {} AuthenticationServiceFake::~AuthenticationServiceFake() {} @@ -48,12 +48,13 @@ completion(); } -void AuthenticationServiceFake::SetHaveAccountsChanged(bool changed) { - have_accounts_changed_ = changed; +void AuthenticationServiceFake::SetHaveAccountsChangedWhileInBackground( + bool changed) { + have_accounts_changed_while_in_background_ = changed; } -bool AuthenticationServiceFake::HaveAccountsChanged() const { - return have_accounts_changed_; +bool AuthenticationServiceFake::HaveAccountsChangedWhileInBackground() const { + return have_accounts_changed_while_in_background_; } bool AuthenticationServiceFake::IsAuthenticated() const {
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm index 52dd32a..8aa0116b 100644 --- a/ios/chrome/browser/signin/authentication_service_unittest.mm +++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -108,12 +108,12 @@ EXPECT_CALL(*sync_setup_service_mock(), PrepareForFirstSyncSetup()); } - void StoreAccountsInPrefs() { - authentication_service()->StoreAccountsInPrefs(); + void StoreKnownAccountsWhileInForeground() { + authentication_service()->StoreKnownAccountsWhileInForeground(); } - std::vector<std::string> GetAccountsInPrefs() { - return authentication_service()->GetAccountsInPrefs(); + std::vector<std::string> GetLastKnownAccountsFromForeground() { + return authentication_service()->GetLastKnownAccountsFromForeground(); } void FireApplicationWillEnterForeground() { @@ -249,7 +249,7 @@ TEST_F(AuthenticationServiceTest, StoreAndGetAccountsInPrefs) { // Profile starts empty. - std::vector<std::string> accounts = GetAccountsInPrefs(); + std::vector<std::string> accounts = GetLastKnownAccountsFromForeground(); EXPECT_TRUE(accounts.empty()); // Sign in. @@ -258,12 +258,11 @@ // Store the accounts and get them back from the prefs. They should be the // same as the token service accounts. - StoreAccountsInPrefs(); - accounts = GetAccountsInPrefs(); + StoreKnownAccountsWhileInForeground(); + accounts = GetLastKnownAccountsFromForeground(); ASSERT_EQ(2u, accounts.size()); - - EXPECT_EQ("foo2ID", accounts[0]); - EXPECT_EQ("fooID", accounts[1]); + EXPECT_EQ("foo2ID", accounts[0]); + EXPECT_EQ("fooID", accounts[1]); } TEST_F(AuthenticationServiceTest, @@ -282,9 +281,8 @@ identity_manager()->GetAccountsWithRefreshTokens(); std::sort(accounts.begin(), accounts.end(), account_compare_func); ASSERT_EQ(2u, accounts.size()); - - EXPECT_EQ("foo2ID", accounts[0].account_id); - EXPECT_EQ("fooID", accounts[1].account_id); + EXPECT_EQ("foo2ID", accounts[0].account_id); + EXPECT_EQ("fooID", accounts[1].account_id); // Simulate a switching to background and back to foreground, triggering a // credentials reload. @@ -296,13 +294,14 @@ accounts = identity_manager()->GetAccountsWithRefreshTokens(); std::sort(accounts.begin(), accounts.end(), account_compare_func); ASSERT_EQ(3u, accounts.size()); - EXPECT_EQ("foo2ID", accounts[0].account_id); - EXPECT_EQ("foo3ID", accounts[1].account_id); - EXPECT_EQ("fooID", accounts[2].account_id); + EXPECT_EQ("foo2ID", accounts[0].account_id); + EXPECT_EQ("foo3ID", accounts[1].account_id); + EXPECT_EQ("fooID", accounts[2].account_id); } TEST_F(AuthenticationServiceTest, HaveAccountsChanged_Default) { - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); } TEST_F(AuthenticationServiceTest, HaveAccountsChanged_NoChange) { @@ -315,15 +314,18 @@ // If an account is added while the application is in foreground, then the // have accounts changed state should stay false. - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); // Backgrounding the app should not change the have accounts changed state. FireApplicationDidEnterBackground(); - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); // Foregrounding the app should not change the have accounts changed state. FireApplicationWillEnterForeground(); - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); } TEST_F(AuthenticationServiceTest, HaveAccountsChanged_ChangedInBackground) { @@ -333,14 +335,15 @@ identity_service()->AddIdentities(@[ @"foo3" ]); FireIdentityListChanged(); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); // Simulate a switching to background and back to foreground, changing the // accounts while in background (no notification fired by |identity_service|). FireApplicationDidEnterBackground(); identity_service()->AddIdentities(@[ @"foo4" ]); FireApplicationWillEnterForeground(); - EXPECT_TRUE(authentication_service()->HaveAccountsChanged()); + EXPECT_TRUE(authentication_service()->HaveAccountsChangedWhileInBackground()); } TEST_F(AuthenticationServiceTest, HaveAccountsChanged_CalledInBackground) { @@ -350,7 +353,8 @@ identity_service()->AddIdentities(@[ @"foo3" ]); FireIdentityListChanged(); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); // Simulate a switching to background, changing the accounts while in // background. @@ -358,11 +362,11 @@ identity_service()->AddIdentities(@[ @"foo4" ]); FireIdentityListChanged(); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(authentication_service()->HaveAccountsChanged()); + EXPECT_TRUE(authentication_service()->HaveAccountsChangedWhileInBackground()); // Entering foreground should not change the have accounts changed state. FireApplicationWillEnterForeground(); - EXPECT_TRUE(authentication_service()->HaveAccountsChanged()); + EXPECT_TRUE(authentication_service()->HaveAccountsChangedWhileInBackground()); } // Regression test for http://crbug.com/1006717 @@ -373,7 +377,8 @@ identity_service()->AddIdentities(@[ @"foo3" ]); FireIdentityListChanged(); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); // Simulate a switching to background, changing the accounts while in // background. @@ -386,14 +391,15 @@ // When entering foreground, the have accounts changed state should be // updated. FireApplicationWillEnterForeground(); - EXPECT_TRUE(authentication_service()->HaveAccountsChanged()); + EXPECT_TRUE(authentication_service()->HaveAccountsChangedWhileInBackground()); // Backgrounding and foregrounding the application a second time should update // the list of accounts in |kSigninLastAccounts| and should reset the have // account changed state. FireApplicationDidEnterBackground(); FireApplicationWillEnterForeground(); - EXPECT_FALSE(authentication_service()->HaveAccountsChanged()); + EXPECT_FALSE( + authentication_service()->HaveAccountsChangedWhileInBackground()); } TEST_F(AuthenticationServiceTest, IsAuthenticatedBackground) {
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm index 507d7dfe..5ceb7be 100644 --- a/ios/chrome/browser/tabs/tab_model.mm +++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -574,11 +574,14 @@ int oldCount = _webStateList->count(); DCHECK_GE(oldCount, 0); - web::WebState::CreateParams createParams(_browserState); - DeserializeWebStateList( - _webStateList, window, - base::BindRepeating(&web::WebState::CreateWithStorageSession, - createParams)); + _webStateList->PerformBatchOperation( + base::BindOnce(^(WebStateList* web_state_list) { + web::WebState::CreateParams createParams(_browserState); + DeserializeWebStateList( + web_state_list, window, + base::BindRepeating(&web::WebState::CreateWithStorageSession, + createParams)); + })); DCHECK_GT(_webStateList->count(), oldCount); int restoredCount = _webStateList->count() - oldCount;
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.mm index d1762cc..afcb362 100644 --- a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.mm +++ b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.mm
@@ -206,11 +206,12 @@ if (prevSessionInfo.isFirstSessionAfterUpgrade && [prevSessionInfo.previousSessionVersion hasPrefix:@"77."]) { // In M77, showing the signed-in account view was disabled due to the fact - // that the preferences used to compute authService->HaveAccountsChanged() - // were not correctly updated (see crbug.com/1006717). - // To avoid user confusion, it is important to avoid showing the signed-in - // accounts dialog on the first session after an update from M77 in order - // to allow the authentication service to update its internal preferences. + // that the preferences used to compute + // authService->HaveAccountsChangedWhileInBackground() were not correctly + // updated (see crbug.com/1006717). To avoid user confusion, it is important + // to avoid showing the signed-in accounts dialog on the first session after + // an update from M77 in order to allow the authentication service to update + // its internal preferences. // // TODO(crbug.com/1007990) Remove this code after M81 (revert // https://chromium-review.googlesource.com/c/chromium/src/+/1824259 ). @@ -220,7 +221,8 @@ AuthenticationService* authService = AuthenticationServiceFactory::GetForBrowserState(browserState); return !gSignedInAccountsViewControllerIsShown && - authService->IsAuthenticated() && authService->HaveAccountsChanged(); + authService->IsAuthenticated() && + authService->HaveAccountsChangedWhileInBackground(); } #pragma mark Initialization
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm index b46bb33..aeb2ca8c 100644 --- a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm
@@ -63,7 +63,7 @@ // have changed. TEST_F(SignedInAccountsViewControllerTest, ShouldBePresentedForBrowserStateNecessary) { - auth_service_->SetHaveAccountsChanged(true); + auth_service_->SetHaveAccountsChangedWhileInBackground(true); EXPECT_TRUE([SignedInAccountsViewController shouldBePresentedForBrowserState:browser_state_.get()]); } @@ -72,7 +72,7 @@ // session after upgrade. TEST_F(SignedInAccountsViewControllerTest, ShouldBePresentedForBrowserStateAfterUpgrade) { - auth_service_->SetHaveAccountsChanged(true); + auth_service_->SetHaveAccountsChangedWhileInBackground(true); { [PreviousSessionInfo resetSharedInstanceForTesting];
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm index 4ad14fa..cb925d1 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
@@ -330,26 +330,11 @@ - (void)undoCloseAllItems { if (!self.closedSessionWindow) return; - DCHECK(self.tabModel.browserState); - // Don't trigger the initial load for these restored WebStates since the - // number of WKWebViews is unbounded and may lead to an OOM crash. - WebStateListWebUsageEnabler* webUsageEnabler = - WebStateListWebUsageEnablerFactory::GetInstance()->GetForBrowserState( - self.tabModel.browserState); - webUsageEnabler->SetTriggersInitialLoad(false); - web::WebState::CreateParams createParams(self.tabModel.browserState); - DeserializeWebStateList( - self.webStateList, self.closedSessionWindow, - base::BindRepeating(&web::WebState::CreateWithStorageSession, - createParams)); - webUsageEnabler->SetTriggersInitialLoad(true); - - self.closedSessionWindow = nil; - [self removeEntriesFromTabRestoreService]; - self.closedTabsCount = 0; - // Unmark all images for deletion since they are now active tabs again. - ios::ChromeBrowserState* browserState = self.tabModel.browserState; - [SnapshotCacheFactory::GetForBrowserState(browserState) unmarkAllImages]; + __weak TabGridMediator* weakSelf = self; + self.webStateList->PerformBatchOperation( + base::BindOnce(^(WebStateList* web_state_list) { + [weakSelf restoreClosedSessionWindowAndUpdateTabRestoreService]; + })); } - (void)discardSavedClosedItems { @@ -451,6 +436,33 @@ } } +// Restores the saved |self.closedSessionWindow| and updates the +// TabRestoreService. +- (void)restoreClosedSessionWindowAndUpdateTabRestoreService { + if (!self.closedSessionWindow) + return; + DCHECK(self.tabModel.browserState); + // Don't trigger the initial load for these restored WebStates since the + // number of WKWebViews is unbounded and may lead to an OOM crash. + WebStateListWebUsageEnabler* webUsageEnabler = + WebStateListWebUsageEnablerFactory::GetInstance()->GetForBrowserState( + self.tabModel.browserState); + webUsageEnabler->SetTriggersInitialLoad(false); + web::WebState::CreateParams createParams(self.tabModel.browserState); + DeserializeWebStateList( + self.webStateList, self.closedSessionWindow, + base::BindRepeating(&web::WebState::CreateWithStorageSession, + createParams)); + webUsageEnabler->SetTriggersInitialLoad(true); + + self.closedSessionWindow = nil; + [self removeEntriesFromTabRestoreService]; + self.closedTabsCount = 0; + // Unmark all images for deletion since they are now active tabs again. + ios::ChromeBrowserState* browserState = self.tabModel.browserState; + [SnapshotCacheFactory::GetForBrowserState(browserState) unmarkAllImages]; +} + // Returns a SnapshotCache for the current BrowserState. - (SnapshotCache*)snapshotCache { if (!_tabModel.browserState)
diff --git a/ios/chrome/browser/web_state_list/web_state_list_serialization.mm b/ios/chrome/browser/web_state_list/web_state_list_serialization.mm index d56339e9..f21dca8 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_serialization.mm +++ b/ios/chrome/browser/web_state_list/web_state_list_serialization.mm
@@ -27,54 +27,6 @@ // the WebStates stored in the WebStateList. NSString* const kOpenerIndexKey = @"OpenerIndex"; NSString* const kOpenerNavigationIndexKey = @"OpenerNavigationIndex"; - -// Helper for DeserializeWebStateList allowing the mutation to appears as a -// single batched operation. -void DeserializeWebStateListHelper(SessionWindowIOS* session_window, - const WebStateFactory& web_state_factory, - WebStateList* web_state_list) { - const int old_count = web_state_list->count(); - for (CRWSessionStorage* session in session_window.sessions) { - std::unique_ptr<web::WebState> web_state = web_state_factory.Run(session); - web_state_list->InsertWebState( - web_state_list->count(), std::move(web_state), - WebStateList::INSERT_FORCE_INDEX, WebStateOpener()); - } - - // Restore the WebStates opener-opened relationship. - for (int index = old_count; index < web_state_list->count(); ++index) { - web::WebState* web_state = web_state_list->GetWebStateAt(index); - web::SerializableUserDataManager* user_data_manager = - web::SerializableUserDataManager::FromWebState(web_state); - - NSNumber* boxed_opener_index = base::mac::ObjCCast<NSNumber>( - user_data_manager->GetValueForSerializationKey(kOpenerIndexKey)); - - NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( - user_data_manager->GetValueForSerializationKey( - kOpenerNavigationIndexKey)); - - if (!boxed_opener_index || !boxed_opener_navigation_index) - continue; - - // If opener index is out of bound then assume there is no opener. - const int opener_index = [boxed_opener_index intValue] + old_count; - if (opener_index < old_count || opener_index >= web_state_list->count()) - continue; - - web::WebState* opener = web_state_list->GetWebStateAt(opener_index); - web_state_list->SetOpenerOfWebStateAt( - index, - WebStateOpener(opener, [boxed_opener_navigation_index intValue])); - } - - if (session_window.selectedIndex != NSNotFound) { - DCHECK_LT(session_window.selectedIndex, session_window.sessions.count); - DCHECK_LT(session_window.selectedIndex, static_cast<NSUInteger>(INT_MAX)); - web_state_list->ActivateWebStateAt( - old_count + static_cast<int>(session_window.selectedIndex)); - } -} } // namespace SessionWindowIOS* SerializeWebStateList(WebStateList* web_state_list) { @@ -116,7 +68,45 @@ void DeserializeWebStateList(WebStateList* web_state_list, SessionWindowIOS* session_window, const WebStateFactory& web_state_factory) { - web_state_list->PerformBatchOperation( - base::BindOnce(&DeserializeWebStateListHelper, - base::Unretained(session_window), web_state_factory)); + const int old_count = web_state_list->count(); + for (CRWSessionStorage* session in session_window.sessions) { + std::unique_ptr<web::WebState> web_state = web_state_factory.Run(session); + web_state_list->InsertWebState( + web_state_list->count(), std::move(web_state), + WebStateList::INSERT_FORCE_INDEX, WebStateOpener()); + } + + // Restore the WebStates opener-opened relationship. + for (int index = old_count; index < web_state_list->count(); ++index) { + web::WebState* web_state = web_state_list->GetWebStateAt(index); + web::SerializableUserDataManager* user_data_manager = + web::SerializableUserDataManager::FromWebState(web_state); + + NSNumber* boxed_opener_index = base::mac::ObjCCast<NSNumber>( + user_data_manager->GetValueForSerializationKey(kOpenerIndexKey)); + + NSNumber* boxed_opener_navigation_index = base::mac::ObjCCast<NSNumber>( + user_data_manager->GetValueForSerializationKey( + kOpenerNavigationIndexKey)); + + if (!boxed_opener_index || !boxed_opener_navigation_index) + continue; + + // If opener index is out of bound then assume there is no opener. + const int opener_index = [boxed_opener_index intValue] + old_count; + if (opener_index < old_count || opener_index >= web_state_list->count()) + continue; + + web::WebState* opener = web_state_list->GetWebStateAt(opener_index); + web_state_list->SetOpenerOfWebStateAt( + index, + WebStateOpener(opener, [boxed_opener_navigation_index intValue])); + } + + if (session_window.selectedIndex != NSNotFound) { + DCHECK_LT(session_window.selectedIndex, session_window.sessions.count); + DCHECK_LT(session_window.selectedIndex, static_cast<NSUInteger>(INT_MAX)); + web_state_list->ActivateWebStateAt( + old_count + static_cast<int>(session_window.selectedIndex)); + } }
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc index 0d28566..2858f46 100644 --- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -66,17 +66,18 @@ class MojoCameraClientObserver : public CameraClientObserver { public: - explicit MojoCameraClientObserver(cros::mojom::CameraHalClientPtr client) + explicit MojoCameraClientObserver( + mojo::PendingRemote<cros::mojom::CameraHalClient> client) : client_(std::move(client)) {} void OnChannelCreated(cros::mojom::CameraModulePtr camera_module) override { client_->SetUpChannel(std::move(camera_module)); } - cros::mojom::CameraHalClientPtr& client() { return client_; } + mojo::Remote<cros::mojom::CameraHalClient>& client() { return client_; } private: - cros::mojom::CameraHalClientPtr client_; + mojo::Remote<cros::mojom::CameraHalClient> client_; DISALLOW_IMPLICIT_CONSTRUCTORS(MojoCameraClientObserver); }; @@ -164,17 +165,17 @@ } void CameraHalDispatcherImpl::RegisterServer( - cros::mojom::CameraHalServerPtr camera_hal_server) { + mojo::PendingRemote<cros::mojom::CameraHalServer> camera_hal_server) { DCHECK(proxy_task_runner_->BelongsToCurrentThread()); if (camera_hal_server_) { LOG(ERROR) << "Camera HAL server is already registered"; return; } - camera_hal_server.set_connection_error_handler( + camera_hal_server_.Bind(std::move(camera_hal_server)); + camera_hal_server_.set_disconnect_handler( base::BindOnce(&CameraHalDispatcherImpl::OnCameraHalServerConnectionError, base::Unretained(this))); - camera_hal_server_ = std::move(camera_hal_server); VLOG(1) << "Camera HAL server registered"; // Set up the Mojo channels for clients which registered before the server @@ -185,14 +186,14 @@ } void CameraHalDispatcherImpl::RegisterClient( - cros::mojom::CameraHalClientPtr client) { + mojo::PendingRemote<cros::mojom::CameraHalClient> client) { // RegisterClient can be called locally by ArcCameraBridge. Unretained // reference is safe here because CameraHalDispatcherImpl owns // |proxy_thread_|. proxy_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImpl::RegisterClientOnProxyThread, - base::Unretained(this), client.PassInterface())); + base::Unretained(this), std::move(client))); } void CameraHalDispatcherImpl::GetJpegDecodeAccelerator( @@ -333,12 +334,11 @@ } void CameraHalDispatcherImpl::RegisterClientOnProxyThread( - mojo::InterfacePtrInfo<cros::mojom::CameraHalClient> client_ptr_info) { + mojo::PendingRemote<cros::mojom::CameraHalClient> client) { DCHECK(proxy_task_runner_->BelongsToCurrentThread()); - cros::mojom::CameraHalClientPtr client_ptr(std::move(client_ptr_info)); auto client_observer = - std::make_unique<MojoCameraClientObserver>(std::move(client_ptr)); - client_observer->client().set_connection_error_handler(base::BindOnce( + std::make_unique<MojoCameraClientObserver>(std::move(client)); + client_observer->client().set_disconnect_handler(base::BindOnce( &CameraHalDispatcherImpl::OnCameraHalClientConnectionError, base::Unretained(this), base::Unretained(client_observer.get()))); AddClientObserver(std::move(client_observer)); @@ -367,8 +367,9 @@ void CameraHalDispatcherImpl::OnPeerConnected( mojo::ScopedMessagePipeHandle message_pipe) { DCHECK(proxy_task_runner_->BelongsToCurrentThread()); - binding_set_.AddBinding( - this, cros::mojom::CameraHalDispatcherRequest(std::move(message_pipe))); + receiver_set_.Add(this, + mojo::PendingReceiver<cros::mojom::CameraHalDispatcher>( + std::move(message_pipe))); VLOG(1) << "New CameraHalDispatcher binding added"; } @@ -398,7 +399,7 @@ cancel_pipe_.reset(); client_observers_.clear(); camera_hal_server_.reset(); - binding_set_.CloseAllBindings(); + receiver_set_.Clear(); } void CameraHalDispatcherImpl::OnTraceLogEnabledOnProxyThread() {
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h index 0c34d6f..b8370d00 100644 --- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -18,8 +18,10 @@ #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" #include "media/capture/video/video_capture_device_factory.h" -#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/platform/platform_channel_server_endpoint.h" namespace base { @@ -64,8 +66,10 @@ bool IsStarted(); // CameraHalDispatcher implementations. - void RegisterServer(cros::mojom::CameraHalServerPtr server) final; - void RegisterClient(cros::mojom::CameraHalClientPtr client) final; + void RegisterServer( + mojo::PendingRemote<cros::mojom::CameraHalServer> server) final; + void RegisterClient( + mojo::PendingRemote<cros::mojom::CameraHalClient> client) final; void GetJpegDecodeAccelerator( mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator> jda_receiver) final; @@ -96,7 +100,7 @@ void StartServiceLoop(base::ScopedFD socket_fd, base::WaitableEvent* started); void RegisterClientOnProxyThread( - mojo::InterfacePtrInfo<cros::mojom::CameraHalClient> client_ptr_info); + mojo::PendingRemote<cros::mojom::CameraHalClient> client); void AddClientObserverOnProxyThread( std::unique_ptr<CameraClientObserver> observer); @@ -122,9 +126,9 @@ scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> blocking_io_task_runner_; - mojo::BindingSet<cros::mojom::CameraHalDispatcher> binding_set_; + mojo::ReceiverSet<cros::mojom::CameraHalDispatcher> receiver_set_; - cros::mojom::CameraHalServerPtr camera_hal_server_; + mojo::Remote<cros::mojom::CameraHalServer> camera_hal_server_; std::set<std::unique_ptr<CameraClientObserver>, base::UniquePtrComparator> client_observers_;
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc index 80aa63cd..e93be07 100644 --- a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -13,7 +13,8 @@ #include "base/test/task_environment.h" #include "media/capture/video/chromeos/mojom/camera_common.mojom.h" #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,7 +26,7 @@ class MockCameraHalServer : public cros::mojom::CameraHalServer { public: - MockCameraHalServer() : binding_(this) {} + MockCameraHalServer() = default; ~MockCameraHalServer() = default; @@ -38,22 +39,18 @@ MOCK_METHOD1(SetTracingEnabled, void(bool enabled)); - cros::mojom::CameraHalServerPtrInfo GetInterfacePtrInfo() { - cros::mojom::CameraHalServerPtrInfo camera_hal_server_ptr_info; - cros::mojom::CameraHalServerRequest camera_hal_server_request = - mojo::MakeRequest(&camera_hal_server_ptr_info); - binding_.Bind(std::move(camera_hal_server_request)); - return camera_hal_server_ptr_info; + mojo::PendingRemote<cros::mojom::CameraHalServer> GetPendingRemote() { + return receiver_.BindNewPipeAndPassRemote(); } private: - mojo::Binding<cros::mojom::CameraHalServer> binding_; + mojo::Receiver<cros::mojom::CameraHalServer> receiver_{this}; DISALLOW_COPY_AND_ASSIGN(MockCameraHalServer); }; class MockCameraHalClient : public cros::mojom::CameraHalClient { public: - MockCameraHalClient() : binding_(this) {} + MockCameraHalClient() = default; ~MockCameraHalClient() = default; @@ -63,16 +60,12 @@ MOCK_METHOD1(DoSetUpChannel, void(cros::mojom::CameraModulePtr& camera_module_ptr)); - cros::mojom::CameraHalClientPtrInfo GetInterfacePtrInfo() { - cros::mojom::CameraHalClientPtrInfo camera_hal_client_ptr_info; - cros::mojom::CameraHalClientRequest camera_hal_client_request = - mojo::MakeRequest(&camera_hal_client_ptr_info); - binding_.Bind(std::move(camera_hal_client_request)); - return camera_hal_client_ptr_info; + mojo::PendingRemote<cros::mojom::CameraHalClient> GetPendingRemote() { + return receiver_.BindNewPipeAndPassRemote(); } private: - mojo::Binding<cros::mojom::CameraHalClient> binding_; + mojo::Receiver<cros::mojom::CameraHalClient> receiver_{this}; DISALLOW_COPY_AND_ASSIGN(MockCameraHalClient); }; @@ -106,14 +99,16 @@ } } - static void RegisterServer(CameraHalDispatcherImpl* dispatcher, - cros::mojom::CameraHalServerPtrInfo server) { - dispatcher->RegisterServer(mojo::MakeProxy(std::move(server))); + static void RegisterServer( + CameraHalDispatcherImpl* dispatcher, + mojo::PendingRemote<cros::mojom::CameraHalServer> server) { + dispatcher->RegisterServer(std::move(server)); } - static void RegisterClient(CameraHalDispatcherImpl* dispatcher, - cros::mojom::CameraHalClientPtrInfo client) { - dispatcher->RegisterClient(mojo::MakeProxy(std::move(client))); + static void RegisterClient( + CameraHalDispatcherImpl* dispatcher, + mojo::PendingRemote<cros::mojom::CameraHalClient> client) { + dispatcher->RegisterClient(std::move(client)); } protected: @@ -141,16 +136,16 @@ .WillOnce( InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); - auto server_ptr = mock_server->GetInterfacePtrInfo(); + auto server = mock_server->GetPendingRemote(); GetProxyTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer, - base::Unretained(dispatcher_), base::Passed(&server_ptr))); - auto client_ptr = mock_client->GetInterfacePtrInfo(); + base::Unretained(dispatcher_), std::move(server))); + auto client = mock_client->GetPendingRemote(); GetProxyTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImplTest::RegisterClient, - base::Unretained(dispatcher_), base::Passed(&client_ptr))); + base::Unretained(dispatcher_), std::move(client))); // Wait until the client gets the established Mojo channel. DoLoop(); @@ -166,11 +161,11 @@ .WillOnce( InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); - server_ptr = mock_server->GetInterfacePtrInfo(); + server = mock_server->GetPendingRemote(); GetProxyTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer, - base::Unretained(dispatcher_), base::Passed(&server_ptr))); + base::Unretained(dispatcher_), std::move(server))); // Wait until the clients gets the newly established Mojo channel. DoLoop(); @@ -190,16 +185,16 @@ .WillOnce( InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); - auto server_ptr = mock_server->GetInterfacePtrInfo(); + auto server = mock_server->GetPendingRemote(); GetProxyTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer, - base::Unretained(dispatcher_), base::Passed(&server_ptr))); - auto client_ptr = mock_client->GetInterfacePtrInfo(); + base::Unretained(dispatcher_), std::move(server))); + auto client = mock_client->GetPendingRemote(); GetProxyTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImplTest::RegisterClient, - base::Unretained(dispatcher_), base::Passed(&client_ptr))); + base::Unretained(dispatcher_), std::move(client))); // Wait until the client gets the established Mojo channel. DoLoop(); @@ -215,11 +210,11 @@ .WillOnce( InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop)); - client_ptr = mock_client->GetInterfacePtrInfo(); + client = mock_client->GetPendingRemote(); GetProxyTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImplTest::RegisterClient, - base::Unretained(dispatcher_), base::Passed(&client_ptr))); + base::Unretained(dispatcher_), std::move(client))); // Wait until the clients gets the newly established Mojo channel. DoLoop();
diff --git a/media/capture/video/chromeos/mojom/cros_camera_service.mojom b/media/capture/video/chromeos/mojom/cros_camera_service.mojom index d2bd0f2..a8e388c 100644 --- a/media/capture/video/chromeos/mojom/cros_camera_service.mojom +++ b/media/capture/video/chromeos/mojom/cros_camera_service.mojom
@@ -21,11 +21,11 @@ interface CameraHalDispatcher { // A CameraHalServer calls RegisterServer to register itself with the // dispatcher. - RegisterServer@0(CameraHalServer server); + RegisterServer@0(pending_remote<CameraHalServer> server); // A CameraHalClient calls RegisterClient to register itself with the // dispatcher. - RegisterClient@1(CameraHalClient client); + RegisterClient@1(pending_remote<CameraHalClient> client); // Get JpegDecodeAccelerator from dispatcher. [MinVersion=1] GetJpegDecodeAccelerator@2(
diff --git a/media/gpu/linux/video_decoder_pipeline.cc b/media/gpu/linux/video_decoder_pipeline.cc index 58d0a3c..9777c07 100644 --- a/media/gpu/linux/video_decoder_pipeline.cc +++ b/media/gpu/linux/video_decoder_pipeline.cc
@@ -108,25 +108,19 @@ int VideoDecoderPipeline::GetMaxDecodeRequests() const { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - if (!decoder_) - DVLOGF(1) << "Call before Initialize() success."; - return decoder_ ? decoder_->GetMaxDecodeRequests() : 1; + return 4; } bool VideoDecoderPipeline::NeedsBitstreamConversion() const { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - if (!decoder_) - DVLOGF(1) << "Call before Initialize() success."; - return decoder_ ? decoder_->NeedsBitstreamConversion() : false; + return needs_bitstream_conversion_; } bool VideoDecoderPipeline::CanReadWithoutStalling() const { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - if (!decoder_) - DVLOGF(1) << "Call before Initialize() success."; - return decoder_ ? decoder_->CanReadWithoutStalling() : false; + return frame_pool_ && !frame_pool_->IsExhausted(); } void VideoDecoderPipeline::Initialize(const VideoDecoderConfig& config, @@ -139,35 +133,46 @@ DCHECK(!init_cb_); VLOGF(2) << "config: " << config.AsHumanReadableString(); + if (!config.IsValidConfig()) { + VLOGF(1) << "config is not valid"; + std::move(init_cb).Run(false); + return; + } + if (config.is_encrypted()) { + VLOGF(1) << "Encrypted streams are not supported for this VD"; + std::move(init_cb).Run(false); + return; + } + if (cdm_context) { + VLOGF(1) << "cdm_context is not supported."; + std::move(init_cb).Run(false); + return; + } + + needs_bitstream_conversion_ = (config.codec() == kCodecH264); client_output_cb_ = std::move(output_cb); init_cb_ = std::move(init_cb); base::queue<VideoDecoderPipeline::CreateVDFunc> create_vd_funcs = get_create_vd_functions_cb_.Run(used_create_vd_func_); if (!decoder_) { - CreateAndInitializeVD(std::move(create_vd_funcs), config, low_delay, - cdm_context, waiting_cb); + CreateAndInitializeVD(std::move(create_vd_funcs), config); } else { decoder_->Initialize( - config, low_delay, cdm_context, + config, // If it fails to re-initialize current |decoder_|, it will create // another decoder instance by trying available VD creation functions // again. See |OnInitializeDone| for detail. base::BindOnce(&VideoDecoderPipeline::OnInitializeDone, weak_this_, - std::move(create_vd_funcs), config, low_delay, - cdm_context, waiting_cb), + std::move(create_vd_funcs), config), base::BindRepeating(&VideoDecoderPipeline::OnFrameDecodedThunk, - client_task_runner_, weak_this_), - waiting_cb); + client_task_runner_, weak_this_)); } } void VideoDecoderPipeline::CreateAndInitializeVD( base::queue<VideoDecoderPipeline::CreateVDFunc> create_vd_funcs, - VideoDecoderConfig config, - bool low_delay, - CdmContext* cdm_context, - WaitingCB waiting_cb) { + VideoDecoderConfig config) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); DCHECK(init_cb_); DCHECK(!decoder_); @@ -189,26 +194,20 @@ if (!decoder_) { DVLOGF(2) << "Failed to create VideoDecoder."; used_create_vd_func_ = nullptr; - return CreateAndInitializeVD(std::move(create_vd_funcs), config, low_delay, - cdm_context, std::move(waiting_cb)); + return CreateAndInitializeVD(std::move(create_vd_funcs), config); } decoder_->Initialize( - config, low_delay, cdm_context, + config, base::BindOnce(&VideoDecoderPipeline::OnInitializeDone, weak_this_, - std::move(create_vd_funcs), config, low_delay, cdm_context, - waiting_cb), + std::move(create_vd_funcs), config), base::BindRepeating(&VideoDecoderPipeline::OnFrameDecodedThunk, - client_task_runner_, weak_this_), - waiting_cb); + client_task_runner_, weak_this_)); } void VideoDecoderPipeline::OnInitializeDone( base::queue<VideoDecoderPipeline::CreateVDFunc> create_vd_funcs, VideoDecoderConfig config, - bool low_delay, - CdmContext* cdm_context, - WaitingCB waiting_cb, bool success) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); DCHECK(init_cb_); @@ -223,8 +222,7 @@ DVLOGF(3) << "Reset VD, try the next create function."; decoder_ = nullptr; used_create_vd_func_ = nullptr; - CreateAndInitializeVD(std::move(create_vd_funcs), config, low_delay, - cdm_context, std::move(waiting_cb)); + CreateAndInitializeVD(std::move(create_vd_funcs), config); } void VideoDecoderPipeline::Reset(base::OnceClosure closure) {
diff --git a/media/gpu/linux/video_decoder_pipeline.h b/media/gpu/linux/video_decoder_pipeline.h index 85014b1..32aa613 100644 --- a/media/gpu/linux/video_decoder_pipeline.h +++ b/media/gpu/linux/video_decoder_pipeline.h
@@ -26,8 +26,66 @@ class MEDIA_GPU_EXPORT VideoDecoderPipeline : public VideoDecoder { public: + // An interface that defines methods to operate on video decoder components + // inside the VideoDecoderPipeline. The interface is similar to + // media::VideoDecoder. The reason not using media::VideoDecoder is that some + // decoders might need to attach an image processor to perform frame + // processing, the output of VideoDecoder is not suitable when the + // intermediate output cannot be rendered by the compositor. + // + // Note: All methods and callbacks should be called on the same sequence. + class MEDIA_GPU_EXPORT DecoderInterface { + public: + using InitCB = base::OnceCallback<void(bool success)>; + // TODO(crbug.com/998413): Replace VideoFrame to GpuMemoryBuffer-based + // instance. + using OutputCB = base::RepeatingCallback<void(scoped_refptr<VideoFrame>)>; + using DecodeCB = base::OnceCallback<void(DecodeStatus)>; + + DecoderInterface() = default; + virtual ~DecoderInterface() = default; + + // Initializes a DecoderInterface with the given |config|, executing the + // |init_cb| upon completion. |output_cb| is called for each output frame + // decoded by Decode(). + // + // Note: + // 1) DecoderInterface will be reinitialized if it was initialized before. + // 2) This method should not be called during pending decode or reset. + // 3) No DecoderInterface calls should be made before |init_cb| is executed + // successfully. + // TODO(akahuang): Add an error notification method to handle misused case. + // 4) |init_cb| may be called before this returns. + virtual void Initialize(const VideoDecoderConfig& config, + InitCB init_cb, + const OutputCB& output_cb) = 0; + + // Requests a |buffer| to be decoded. The decode result will be returned via + // |decode_cb|. + // + // After decoding is finished the decoder calls |output_cb| specified in + // Initialize() for each decoded frame. |output_cb| may be called before or + // after |decode_cb|, including before Decode() returns. + // + // If |buffer| is an EOS buffer then the decoder must be flushed, i.e. + // |output_cb| must be called for each frame pending in the queue and + // |decode_cb| must be called after that. Callers will not call Decode() + // again until after the flush completes. + // TODO(akahuang): Add an error notification method to handle misused case. + virtual void Decode(scoped_refptr<DecoderBuffer> buffer, + DecodeCB decode_cb) = 0; + + // Resets decoder state. All pending Decode() requests will be finished or + // aborted before |closure| is called. + // Note: No VideoDecoder calls should be made before |closure| is executed. + // TODO(akahuang): Add an error notification method to handle misused case. + virtual void Reset(base::OnceClosure closure) = 0; + + DISALLOW_COPY_AND_ASSIGN(DecoderInterface); + }; + // Function signature for creating VideoDecoder. - using CreateVDFunc = std::unique_ptr<VideoDecoder> (*)( + using CreateVDFunc = std::unique_ptr<DecoderInterface> (*)( scoped_refptr<base::SequencedTaskRunner>, scoped_refptr<base::SequencedTaskRunner>, base::RepeatingCallback<DmabufVideoFramePool*()>); @@ -72,15 +130,9 @@ void DestroyTask(); void CreateAndInitializeVD(base::queue<CreateVDFunc> create_vd_funcs, - VideoDecoderConfig config, - bool low_delay, - CdmContext* cdm_context, - WaitingCB waiting_cb); + VideoDecoderConfig config); void OnInitializeDone(base::queue<CreateVDFunc> create_vd_funcs, VideoDecoderConfig config, - bool low_delay, - CdmContext* cdm_context, - WaitingCB waiting_cb, bool success); void OnDecodeDone(bool eos_buffer, DecodeCB decode_cb, DecodeStatus status); @@ -116,12 +168,12 @@ // |client_task_runner_|. std::unique_ptr<VideoFrameConverter> frame_converter_; - // The callback to get a list of function for creating VideoDecoder. + // The callback to get a list of function for creating DecoderInterface. GetCreateVDFunctionsCB get_create_vd_functions_cb_; // The current video decoder implementation. Valid after initialization is // successfully done. - std::unique_ptr<VideoDecoder> decoder_; + std::unique_ptr<DecoderInterface> decoder_; // The create function of |decoder_|. nullptr iff |decoder_| is nullptr. CreateVDFunc used_create_vd_func_ = nullptr; @@ -132,6 +184,9 @@ DecodeCB client_flush_cb_; base::OnceClosure client_reset_cb_; + // True if the decoder needs bitstream conversion before decoding. + bool needs_bitstream_conversion_ = false; + // Set to true when any unexpected error occurs. bool has_error_ = false;
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc index 3f33618..a43bd70b 100644 --- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc +++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -1501,9 +1501,17 @@ auto output_gmb_handle = CreateGpuMemoryBufferHandle(output_frame.get()); DCHECK(!output_gmb_handle.is_null()); + + // In this case, we use the R_8 buffer with height == 1 to represent a data + // container. As a result, we use plane.stride as size of the data here since + // plane.size might be larger due to height alignment. + const gfx::Size output_gmb_buffer_size( + base::checked_cast<int32_t>(output_frame->layout().planes()[0].stride), + 1); + auto output_gmb_buffer = gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle( - std::move(output_gmb_handle), output_frame->coded_size(), + std::move(output_gmb_handle), output_gmb_buffer_size, gfx::BufferFormat::R_8, gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, base::DoNothing());
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc index d4a716a..aca260b0 100644 --- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -40,7 +40,8 @@ } // namespace // static -std::unique_ptr<VideoDecoder> V4L2SliceVideoDecoder::Create( +std::unique_ptr<VideoDecoderPipeline::DecoderInterface> +V4L2SliceVideoDecoder::Create( scoped_refptr<base::SequencedTaskRunner> client_task_runner, scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, GetFramePoolCB get_pool_cb) { @@ -53,9 +54,10 @@ return nullptr; } - return base::WrapUnique<VideoDecoder>(new V4L2SliceVideoDecoder( - std::move(client_task_runner), std::move(decoder_task_runner), - std::move(device), std::move(get_pool_cb))); + return base::WrapUnique<VideoDecoderPipeline::DecoderInterface>( + new V4L2SliceVideoDecoder(std::move(client_task_runner), + std::move(decoder_task_runner), + std::move(device), std::move(get_pool_cb))); } // static @@ -87,52 +89,20 @@ } V4L2SliceVideoDecoder::~V4L2SliceVideoDecoder() { - // We might be called from either the client or the decoder sequence. - DETACH_FROM_SEQUENCE(client_sequence_checker_); - DETACH_FROM_SEQUENCE(decoder_sequence_checker_); - VLOGF(2); -} - -std::string V4L2SliceVideoDecoder::GetDisplayName() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return "V4L2SliceVideoDecoder"; -} - -bool V4L2SliceVideoDecoder::IsPlatformDecoder() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return true; -} - -int V4L2SliceVideoDecoder::GetMaxDecodeRequests() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return 4; -} - -bool V4L2SliceVideoDecoder::NeedsBitstreamConversion() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return needs_bitstream_conversion_; -} - -bool V4L2SliceVideoDecoder::CanReadWithoutStalling() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return frame_pool_ && !frame_pool_->IsExhausted(); -} - -void V4L2SliceVideoDecoder::Destroy() { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); VLOGF(2); + // We need this event to synchronously destroy this instance. + // TODO(akahuang): Remove this event by manipulating this instance only on one + // sequence. + base::WaitableEvent event; decoder_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&V4L2SliceVideoDecoder::DestroyTask, weak_this_)); + FROM_HERE, base::BindOnce(&V4L2SliceVideoDecoder::DestroyTask, weak_this_, + base::Unretained(&event))); + event.Wait(); } -void V4L2SliceVideoDecoder::DestroyTask() { +void V4L2SliceVideoDecoder::DestroyTask(base::WaitableEvent* event) { DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DVLOGF(2); @@ -155,29 +125,14 @@ weak_this_factory_.InvalidateWeakPtrs(); - delete this; - VLOGF(2) << "Destroyed"; + event->Signal(); } void V4L2SliceVideoDecoder::Initialize(const VideoDecoderConfig& config, - bool low_delay, - CdmContext* cdm_context, InitCB init_cb, - const OutputCB& output_cb, - const WaitingCB& /* waiting_cb */) { + const OutputCB& output_cb) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - VLOGF(2) << "config: " << config.AsHumanReadableString(); - - if (!config.IsValidConfig()) { - VLOGF(1) << "config is not valid"; - std::move(init_cb).Run(false); - return; - } - if (cdm_context) { - VLOGF(1) << "cdm_context is not supported."; - std::move(init_cb).Run(false); - return; - } + DCHECK(config.IsValidConfig()); decoder_task_runner_->PostTask( FROM_HERE, @@ -246,7 +201,6 @@ return; } - needs_bitstream_conversion_ = (config.codec() == kCodecH264); pixel_aspect_ratio_ = config.GetPixelAspectRatio(); // Create Input/Output V4L2Queue @@ -661,10 +615,6 @@ frame = std::move(wrapped_frame); } - // Although the document of VideoDecoder says "should run |output_cb| as soon - // as possible (without thread trampolining)", MojoVideoDecoderService still - // assumes the callback is called at original thread. - // TODO(akahuang): call the callback directly after updating MojoVDService. client_task_runner_->PostTask(FROM_HERE, base::BindOnce(output_cb_, std::move(frame))); }
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h index 5f36a12..89afd737 100644 --- a/media/gpu/v4l2/v4l2_slice_video_decoder.h +++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -21,11 +21,12 @@ #include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" +#include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/time/time.h" -#include "media/base/video_decoder.h" #include "media/base/video_frame_layout.h" #include "media/base/video_types.h" +#include "media/gpu/linux/video_decoder_pipeline.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/v4l2/v4l2_device.h" #include "media/gpu/v4l2/v4l2_video_decoder_backend.h" @@ -36,7 +37,7 @@ class DmabufVideoFramePool; class MEDIA_GPU_EXPORT V4L2SliceVideoDecoder - : public VideoDecoder, + : public VideoDecoderPipeline::DecoderInterface, public V4L2VideoDecoderBackend::Client { public: using GetFramePoolCB = base::RepeatingCallback<DmabufVideoFramePool*()>; @@ -44,26 +45,17 @@ // Create V4L2SliceVideoDecoder instance. The success of the creation doesn't // ensure V4L2SliceVideoDecoder is available on the device. It will be // determined in Initialize(). - static std::unique_ptr<VideoDecoder> Create( + static std::unique_ptr<VideoDecoderPipeline::DecoderInterface> Create( scoped_refptr<base::SequencedTaskRunner> client_task_runner, scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, GetFramePoolCB get_pool_cb); static SupportedVideoDecoderConfigs GetSupportedConfigs(); - // VideoDecoder implementation. - std::string GetDisplayName() const override; - bool IsPlatformDecoder() const override; - int GetMaxDecodeRequests() const override; - bool NeedsBitstreamConversion() const override; - bool CanReadWithoutStalling() const override; - + // VideoDecoderPipeline::DecoderInterface implementation. void Initialize(const VideoDecoderConfig& config, - bool low_delay, - CdmContext* cdm_context, InitCB init_cb, - const OutputCB& output_cb, - const WaitingCB& waiting_cb) override; + const OutputCB& output_cb) override; void Reset(base::OnceClosure closure) override; void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override; @@ -89,7 +81,6 @@ scoped_refptr<V4L2Device> device, GetFramePoolCB get_pool_cb); ~V4L2SliceVideoDecoder() override; - void Destroy() override; enum class State { // Initial state. Transitions to |kDecoding| if Initialize() is successful, @@ -147,7 +138,7 @@ const gfx::Rect& visible_rect); // Destroy on decoder thread. - void DestroyTask(); + void DestroyTask(base::WaitableEvent* event); // Reset on decoder thread. void ResetTask(base::OnceClosure closure); @@ -177,8 +168,8 @@ GetFramePoolCB get_pool_cb_; DmabufVideoFramePool* frame_pool_ = nullptr; - // Client task runner. All public methods of VideoDecoder interface are - // executed at this task runner. + // Client task runner. All public methods of + // VideoDecoderPipeline::DecoderInterface are executed at this task runner. const scoped_refptr<base::SequencedTaskRunner> client_task_runner_; // Thread to communicate with the device on. Most of internal methods and data // members are manipulated on this thread. @@ -201,9 +192,6 @@ BitstreamIdGenerator bitstream_id_generator_; - // True if the decoder needs bitstream conversion before decoding. - bool needs_bitstream_conversion_ = false; - SEQUENCE_CHECKER(client_sequence_checker_); SEQUENCE_CHECKER(decoder_sequence_checker_);
diff --git a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc index f697e0a3..f965406 100644 --- a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc +++ b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
@@ -243,8 +243,13 @@ // size, where buffer_size can be obtained from the first plane's size. auto output_gmb_handle = CreateGpuMemoryBufferHandle(output_frame.get()); DCHECK(!output_gmb_handle.is_null()); + + // In this case, we use the R_8 buffer with height == 1 to represent a data + // container. As a result, we use plane.stride as size of the data here since + // plane.size might be larger due to height alignment. const gfx::Size output_gmb_buffer_size( - base::checked_cast<int32_t>(output_frame->layout().planes()[0].size), 1); + base::checked_cast<int32_t>(output_frame->layout().planes()[0].stride), + 1); auto output_gmb_buffer = gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle( std::move(output_gmb_handle), output_gmb_buffer_size,
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc index 37b7b40b..7dfbaf0 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -27,9 +27,6 @@ namespace { -// Maximum number of parallel decode requests. -constexpr int kMaxDecodeRequests = 4; - // Size of the timestamp cache, needs to be large enough for frame-reordering. constexpr size_t kTimestampCacheSize = 128; @@ -66,13 +63,15 @@ VaapiVideoDecoder::DecodeTask::DecodeTask(DecodeTask&&) = default; // static -std::unique_ptr<VideoDecoder> VaapiVideoDecoder::Create( +std::unique_ptr<VideoDecoderPipeline::DecoderInterface> +VaapiVideoDecoder::Create( scoped_refptr<base::SequencedTaskRunner> client_task_runner, scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, GetFramePoolCB get_pool_cb) { - return base::WrapUnique<VideoDecoder>(new VaapiVideoDecoder( - std::move(client_task_runner), std::move(decoder_task_runner), - std::move(get_pool_cb))); + return base::WrapUnique<VideoDecoderPipeline::DecoderInterface>( + new VaapiVideoDecoder(std::move(client_task_runner), + std::move(decoder_task_runner), + std::move(get_pool_cb))); } // static @@ -96,62 +95,42 @@ weak_this_ = weak_this_factory_.GetWeakPtr(); } -VaapiVideoDecoder::~VaapiVideoDecoder() {} - -std::string VaapiVideoDecoder::GetDisplayName() const { +VaapiVideoDecoder::~VaapiVideoDecoder() { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); + VLOGF(2); - return "VaapiVideoDecoder"; + // We need this event to synchronously destroy this instance. + // TODO(akahuang): Remove this event by manipulating this instance only on one + // sequence. + base::WaitableEvent event; + decoder_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&VaapiVideoDecoder::DestroyTask, weak_this_, + base::Unretained(&event))); + event.Wait(); } -bool VaapiVideoDecoder::IsPlatformDecoder() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); +void VaapiVideoDecoder::DestroyTask(base::WaitableEvent* event) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); + DVLOGF(2); - return true; -} + // Abort all currently scheduled decode tasks. + ClearDecodeTaskQueue(DecodeStatus::ABORTED); -bool VaapiVideoDecoder::NeedsBitstreamConversion() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); + if (decoder_) { + decoder_->Reset(); + decoder_ = nullptr; + } - return needs_bitstream_conversion_; -} + weak_this_factory_.InvalidateWeakPtrs(); -bool VaapiVideoDecoder::CanReadWithoutStalling() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return frame_pool_ && !frame_pool_->IsExhausted(); -} - -int VaapiVideoDecoder::GetMaxDecodeRequests() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - - return kMaxDecodeRequests; + event->Signal(); } void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, - bool low_delay, - CdmContext* cdm_context, InitCB init_cb, - const OutputCB& output_cb, - const WaitingCB& /*waiting_cb*/) { + const OutputCB& output_cb) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - VLOGF(2) << "config: " << config.AsHumanReadableString(); - - if (cdm_context) { - VLOGF(1) << "cdm_context is not supported."; - std::move(init_cb).Run(false); - return; - } - if (!config.IsValidConfig()) { - VLOGF(1) << "config is not valid"; - std::move(init_cb).Run(false); - return; - } - if (config.is_encrypted()) { - VLOGF(1) << "Encrypted streams are not supported for this VD"; - std::move(init_cb).Run(false); - return; - } + DCHECK(config.IsValidConfig()); decoder_task_runner_->PostTask( FROM_HERE, @@ -175,8 +154,8 @@ } // We expect the decoder to have released all output buffers (by the client - // triggering a flush or reset), even if the media::VideoDecoder API doesn't - // explicitly specify this. + // triggering a flush or reset), even if the + // VideoDecoderPipeline::DecoderInterface API doesn't explicitly specify this. DCHECK(output_frames_.empty()); if (state_ != State::kUninitialized) { @@ -219,7 +198,6 @@ base::BindOnce(std::move(init_cb), false)); return; } - needs_bitstream_conversion_ = (config.codec() == kCodecH264); // Get and initialize the frame pool. frame_pool_ = get_pool_cb_.Run(); @@ -235,32 +213,6 @@ base::BindOnce(std::move(init_cb), true)); } -void VaapiVideoDecoder::Destroy() { - DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); - VLOGF(2); - - decoder_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&VaapiVideoDecoder::DestroyTask, weak_this_)); -} - -void VaapiVideoDecoder::DestroyTask() { - DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); - DVLOGF(2); - - // Abort all currently scheduled decode tasks. - ClearDecodeTaskQueue(DecodeStatus::ABORTED); - - if (decoder_) { - decoder_->Reset(); - decoder_ = nullptr; - } - - weak_this_factory_.InvalidateWeakPtrs(); - - delete this; - VLOGF(2) << "Destroying VAAPI VD done"; -} - void VaapiVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); @@ -487,9 +439,6 @@ video_frame = std::move(wrapped_frame); } - // TODO(dstaessens): MojoVideoDecoderService expects the |output_cb_| to be - // called on the client task runner, even though media::VideoDecoder states - // frames should be output without any thread jumping. client_task_runner_->PostTask( FROM_HERE, base::BindOnce(output_cb_, std::move(video_frame))); }
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h index 3c5f8121..7771889 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.h +++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -20,12 +20,13 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/sequence_checker.h" +#include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "media/base/video_codecs.h" -#include "media/base/video_decoder.h" #include "media/base/video_frame_layout.h" #include "media/gpu/decode_surface_handler.h" +#include "media/gpu/linux/video_decoder_pipeline.h" #include "media/video/supported_video_decoder_config.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -38,30 +39,22 @@ class VideoFrame; class VASurface; -class VaapiVideoDecoder : public media::VideoDecoder, +class VaapiVideoDecoder : public VideoDecoderPipeline::DecoderInterface, public DecodeSurfaceHandler<VASurface> { public: using GetFramePoolCB = base::RepeatingCallback<DmabufVideoFramePool*()>; - static std::unique_ptr<VideoDecoder> Create( + static std::unique_ptr<VideoDecoderPipeline::DecoderInterface> Create( scoped_refptr<base::SequencedTaskRunner> client_task_runner, scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, GetFramePoolCB get_pool); static SupportedVideoDecoderConfigs GetSupportedConfigs(); - // media::VideoDecoder implementation. - std::string GetDisplayName() const override; - bool IsPlatformDecoder() const override; - bool NeedsBitstreamConversion() const override; - bool CanReadWithoutStalling() const override; - int GetMaxDecodeRequests() const override; + // VideoDecoderPipeline::DecoderInterface implementation. void Initialize(const VideoDecoderConfig& config, - bool low_delay, - CdmContext* cdm_context, InitCB init_cb, - const OutputCB& output_cb, - const WaitingCB& waiting_cb) override; + const OutputCB& output_cb) override; void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override; void Reset(base::OnceClosure reset_cb) override; @@ -102,16 +95,12 @@ GetFramePoolCB get_pool); ~VaapiVideoDecoder() override; - // Destroy the VAAPIVideoDecoder, aborts pending decode requests and blocks - // until destroyed. - void Destroy() override; - // Initialize the VAAPI video decoder on the decoder thread. void InitializeTask(const VideoDecoderConfig& config, InitCB init_cb, OutputCB output_cb); // Destroy the VAAPI video decoder on the decoder thread. - void DestroyTask(); + void DestroyTask(base::WaitableEvent* event); // Queue a decode task on the decoder thread. If the decoder is currently // waiting for input buffers decoding will be started. @@ -169,8 +158,6 @@ // The video stream's profile. VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN; - // True if the decoder needs bitstream conversion before decoding. - bool needs_bitstream_conversion_ = false; // Output frame properties. base::Optional<VideoFrameLayout> frame_layout_;
diff --git a/media/mojo/clients/mojo_audio_decoder.cc b/media/mojo/clients/mojo_audio_decoder.cc index 82373666..46c9db6 100644 --- a/media/mojo/clients/mojo_audio_decoder.cc +++ b/media/mojo/clients/mojo_audio_decoder.cc
@@ -25,8 +25,7 @@ : task_runner_(task_runner), pending_remote_decoder_(std::move(remote_decoder)), writer_capacity_( - GetDefaultDecoderBufferConverterCapacity(DemuxerStream::AUDIO)), - client_binding_(this) { + GetDefaultDecoderBufferConverterCapacity(DemuxerStream::AUDIO)) { DVLOG(1) << __func__; } @@ -150,10 +149,7 @@ remote_decoder_.set_disconnect_handler( base::Bind(&MojoAudioDecoder::OnConnectionError, base::Unretained(this))); - mojom::AudioDecoderClientAssociatedPtrInfo client_ptr_info; - client_binding_.Bind(mojo::MakeRequest(&client_ptr_info)); - - remote_decoder_->Construct(std::move(client_ptr_info)); + remote_decoder_->Construct(client_receiver_.BindNewEndpointAndPassRemote()); } void MojoAudioDecoder::OnBufferDecoded(mojom::AudioBufferPtr buffer) {
diff --git a/media/mojo/clients/mojo_audio_decoder.h b/media/mojo/clients/mojo_audio_decoder.h index eafee14..0fbe21b 100644 --- a/media/mojo/clients/mojo_audio_decoder.h +++ b/media/mojo/clients/mojo_audio_decoder.h
@@ -12,8 +12,7 @@ #include "media/base/audio_decoder.h" #include "media/mojo/mojom/audio_decoder.mojom.h" #include "media/mojo/mojom/media_types.mojom.h" -#include "mojo/public/cpp/bindings/associated_binding.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" @@ -82,8 +81,8 @@ uint32_t writer_capacity_ = 0; - // Binding for AudioDecoderClient, bound to the |task_runner_|. - mojo::AssociatedBinding<AudioDecoderClient> client_binding_; + // Receiver for AudioDecoderClient, bound to the |task_runner_|. + mojo::AssociatedReceiver<AudioDecoderClient> client_receiver_{this}; InitCB init_cb_; OutputCB output_cb_;
diff --git a/media/mojo/mojom/audio_decoder.mojom b/media/mojo/mojom/audio_decoder.mojom index 204bf4e1..73b6ac0 100644 --- a/media/mojo/mojom/audio_decoder.mojom +++ b/media/mojo/mojom/audio_decoder.mojom
@@ -11,7 +11,7 @@ // // TODO(sandersd): Rename to Initialize() if/when // media::AudioDecoder::Initialize() is renamed to Configure(). - Construct(associated AudioDecoderClient client); + Construct(pending_associated_remote<AudioDecoderClient> client); // Initializes the AudioDecoder with the audio codec configuration and CDM id. // For the unencrypted streams the |cdm_id| is ignored. Executed the callback
diff --git a/media/mojo/services/mojo_audio_decoder_service.cc b/media/mojo/services/mojo_audio_decoder_service.cc index 2434f71..2bfa5ace 100644 --- a/media/mojo/services/mojo_audio_decoder_service.cc +++ b/media/mojo/services/mojo_audio_decoder_service.cc
@@ -27,7 +27,7 @@ MojoAudioDecoderService::~MojoAudioDecoderService() = default; void MojoAudioDecoderService::Construct( - mojom::AudioDecoderClientAssociatedPtrInfo client) { + mojo::PendingAssociatedRemote<mojom::AudioDecoderClient> client) { DVLOG(1) << __func__; client_.Bind(std::move(client)); }
diff --git a/media/mojo/services/mojo_audio_decoder_service.h b/media/mojo/services/mojo_audio_decoder_service.h index 43f977c..872f9f7 100644 --- a/media/mojo/services/mojo_audio_decoder_service.h +++ b/media/mojo/services/mojo_audio_decoder_service.h
@@ -14,6 +14,8 @@ #include "media/base/audio_decoder.h" #include "media/mojo/mojom/audio_decoder.mojom.h" #include "media/mojo/services/media_mojo_export.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_associated_remote.h" namespace media { @@ -29,7 +31,8 @@ ~MojoAudioDecoderService() final; // mojom::AudioDecoder implementation - void Construct(mojom::AudioDecoderClientAssociatedPtrInfo client) final; + void Construct( + mojo::PendingAssociatedRemote<mojom::AudioDecoderClient> client) final; void Initialize(const AudioDecoderConfig& config, int32_t cdm_id, InitializeCallback callback) final; @@ -69,7 +72,7 @@ MojoCdmServiceContext* const mojo_cdm_service_context_ = nullptr; // The destination for the decoded buffers. - mojom::AudioDecoderClientAssociatedPtr client_; + mojo::AssociatedRemote<mojom::AudioDecoderClient> client_; // Holds the CdmContextRef to keep the CdmContext alive for the lifetime of // the |decoder_|.
diff --git a/net/docs/code-patterns.md b/net/docs/code-patterns.md index 2b89459..97ee64a 100644 --- a/net/docs/code-patterns.md +++ b/net/docs/code-patterns.md
@@ -210,7 +210,7 @@ result = DoLoop(result); if (result != ERR_IO_PENDING && !callback_.is_null()) - base::ResetAndReturn(&callback_).Run(result); + std::move(callback_).Run(result); } * The DoLoop pattern has no concept of different events arriving for
diff --git a/net/docs/life-of-a-feature.md b/net/docs/life-of-a-feature.md index 5d5b783..54ddd50b 100644 --- a/net/docs/life-of-a-feature.md +++ b/net/docs/life-of-a-feature.md
@@ -224,8 +224,7 @@ further expanded upon in [Code Patterns](code-patterns.md), features and changes should be designed such that any callback invocation is the last bit of code executed, and that the callback is accessed via the stack (such -as through the use of either `base::ResetAndReturn(callback_).Run()` or -`std::move(callback_).Run()`. +as through the use of `std::move(callback_).Run()`. ### Specs: What Are They Good For
diff --git a/net/http/http_auth_cache.cc b/net/http/http_auth_cache.cc index dafca1a7..d622aec 100644 --- a/net/http/http_auth_cache.cc +++ b/net/http/http_auth_cache.cc
@@ -65,29 +65,38 @@ namespace net { -HttpAuthCache::HttpAuthCache() = default; +HttpAuthCache::HttpAuthCache(bool key_server_entries_by_network_isolation_key) + : key_server_entries_by_network_isolation_key_( + key_server_entries_by_network_isolation_key) {} HttpAuthCache::~HttpAuthCache() = default; // Performance: O(logN+n), where N is the total number of entries, n is the -// number of realm entries for the given origin. -HttpAuthCache::Entry* HttpAuthCache::Lookup(const GURL& origin, - HttpAuth::Target target, - const std::string& realm, - HttpAuth::Scheme scheme) { - EntryMap::iterator entry_it = LookupEntryIt(origin, target, realm, scheme); +// number of realm entries for the given origin, target, and with a matching +// NetworkIsolationKey. +HttpAuthCache::Entry* HttpAuthCache::Lookup( + const GURL& origin, + HttpAuth::Target target, + const std::string& realm, + HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key) { + EntryMap::iterator entry_it = + LookupEntryIt(origin, target, realm, scheme, network_isolation_key); if (entry_it == entries_.end()) return nullptr; return &(entry_it->second); } // Performance: O(logN+n*m), where N is the total number of entries, n is the -// number of realm entries for the given origin and NIK, m is the number of path -// entries per realm. Both n and m are expected to be small; m is kept small -// because AddPath() only keeps the shallowest entry. -HttpAuthCache::Entry* HttpAuthCache::LookupByPath(const GURL& origin, - HttpAuth::Target target, - const std::string& path) { +// number of realm entries for the given origin, target, and +// NetworkIsolationKey, m is the number of path entries per realm. Both n and m +// are expected to be small; m is kept small because AddPath() only keeps the +// shallowest entry. +HttpAuthCache::Entry* HttpAuthCache::LookupByPath( + const GURL& origin, + HttpAuth::Target target, + const NetworkIsolationKey& network_isolation_key, + const std::string& path) { #if DCHECK_IS_ON() CheckOriginIsValid(origin); CheckPathIsValid(path); @@ -100,7 +109,9 @@ std::string parent_dir = GetParentDirectory(path); // Linear scan through the <scheme, realm> entries for the given origin. - auto entry_range = entries_.equal_range(EntryMapKey(origin, target)); + auto entry_range = entries_.equal_range( + EntryMapKey(origin, target, network_isolation_key, + key_server_entries_by_network_isolation_key_)); auto best_match_it = entries_.end(); size_t best_match_length = 0; for (auto it = entry_range.first; it != entry_range.second; ++it) { @@ -121,13 +132,15 @@ return nullptr; } -HttpAuthCache::Entry* HttpAuthCache::Add(const GURL& origin, - HttpAuth::Target target, - const std::string& realm, - HttpAuth::Scheme scheme, - const std::string& auth_challenge, - const AuthCredentials& credentials, - const std::string& path) { +HttpAuthCache::Entry* HttpAuthCache::Add( + const GURL& origin, + HttpAuth::Target target, + const std::string& realm, + HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key, + const std::string& auth_challenge, + const AuthCredentials& credentials, + const std::string& path) { #if DCHECK_IS_ON() CheckOriginIsValid(origin); CheckPathIsValid(path); @@ -136,23 +149,29 @@ base::TimeTicks now_ticks = tick_clock_->NowTicks(); // Check for existing entry (we will re-use it if present). - HttpAuthCache::Entry* entry = Lookup(origin, target, realm, scheme); + HttpAuthCache::Entry* entry = + Lookup(origin, target, realm, scheme, network_isolation_key); if (!entry) { bool evicted = false; // Failsafe to prevent unbounded memory growth of the cache. // - // Data collected in June of 2019 indicate that the eviction rate is at - // around 0.05%. I.e. 0.05% of the time the number of entries in the cache - // exceed kMaxNumRealmEntries. The evicted entry is roughly half an hour old - // (median), and it's been around 25 minutes since its last use (median). + // Data was collected in June of 2019, before entries were keyed on either + // HttpAuth::Target or NetworkIsolationKey. That data indicated that the + // eviction rate was at around 0.05%. I.e. 0.05% of the time the number of + // entries in the cache exceed kMaxNumRealmEntries. The evicted entry is + // roughly half an hour old (median), and it's been around 25 minutes since + // its last use (median). if (entries_.size() >= kMaxNumRealmEntries) { DLOG(WARNING) << "Num auth cache entries reached limit -- evicting"; EvictLeastRecentlyUsedEntry(); evicted = true; } - entry = &( - entries_.emplace(std::make_pair(EntryMapKey(origin, target), Entry())) - ->second); + entry = &(entries_ + .emplace(std::make_pair( + EntryMapKey(origin, target, network_isolation_key, + key_server_entries_by_network_isolation_key_), + Entry())) + ->second); entry->origin_ = origin; entry->realm_ = realm; entry->scheme_ = scheme; @@ -253,8 +272,10 @@ HttpAuth::Target target, const std::string& realm, HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key, const AuthCredentials& credentials) { - EntryMap::iterator entry_it = LookupEntryIt(origin, target, realm, scheme); + EntryMap::iterator entry_it = + LookupEntryIt(origin, target, realm, scheme, network_isolation_key); if (entry_it == entries_.end()) return false; Entry& entry = entry_it->second; @@ -280,12 +301,15 @@ entries_.clear(); } -bool HttpAuthCache::UpdateStaleChallenge(const GURL& origin, - HttpAuth::Target target, - const std::string& realm, - HttpAuth::Scheme scheme, - const std::string& auth_challenge) { - HttpAuthCache::Entry* entry = Lookup(origin, target, realm, scheme); +bool HttpAuthCache::UpdateStaleChallenge( + const GURL& origin, + HttpAuth::Target target, + const std::string& realm, + HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key, + const std::string& auth_challenge) { + HttpAuthCache::Entry* entry = + Lookup(origin, target, realm, scheme, network_isolation_key); if (!entry) return false; entry->UpdateStaleChallenge(auth_challenge); @@ -294,12 +318,16 @@ } void HttpAuthCache::UpdateAllFrom(const HttpAuthCache& other) { + DCHECK_EQ(key_server_entries_by_network_isolation_key_, + other.key_server_entries_by_network_isolation_key()); + for (auto it = other.entries_.begin(); it != other.entries_.end(); ++it) { // Add an Entry with one of the original entry's paths. const Entry& e = it->second; DCHECK(e.paths_.size() > 0); Entry* entry = Add(e.origin(), it->first.target, e.realm(), e.scheme(), - e.auth_challenge(), e.credentials(), e.paths_.back()); + it->first.network_isolation_key, e.auth_challenge(), + e.credentials(), e.paths_.back()); // Copy all other paths. for (auto it2 = std::next(e.paths_.rbegin()); it2 != e.paths_.rend(); ++it2) entry->AddPath(*it2); @@ -308,14 +336,23 @@ } } -HttpAuthCache::EntryMapKey::EntryMapKey(const GURL& url, - HttpAuth::Target target) - : url(url), target(target) {} +HttpAuthCache::EntryMapKey::EntryMapKey( + const GURL& url, + HttpAuth::Target target, + const NetworkIsolationKey& network_isolation_key, + bool key_server_entries_by_network_isolation_key) + : url(url), + target(target), + network_isolation_key(target == HttpAuth::AUTH_SERVER && + key_server_entries_by_network_isolation_key + ? network_isolation_key + : NetworkIsolationKey()) {} HttpAuthCache::EntryMapKey::~EntryMapKey() = default; bool HttpAuthCache::EntryMapKey::operator<(const EntryMapKey& other) const { - return std::tie(url, target) < std::tie(other.url, other.target); + return std::tie(url, target, network_isolation_key) < + std::tie(other.url, other.target, other.network_isolation_key); } size_t HttpAuthCache::GetEntriesSizeForTesting() { @@ -326,14 +363,17 @@ const GURL& origin, HttpAuth::Target target, const std::string& realm, - HttpAuth::Scheme scheme) { + HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key) { #if DCHECK_IS_ON() CheckOriginIsValid(origin); #endif // Linear scan through the <scheme, realm> entries for the given origin and // NetworkIsolationKey. - auto entry_range = entries_.equal_range(EntryMapKey(origin, target)); + auto entry_range = entries_.equal_range( + EntryMapKey(origin, target, network_isolation_key, + key_server_entries_by_network_isolation_key_)); for (auto it = entry_range.first; it != entry_range.second; ++it) { Entry& entry = it->second; DCHECK(entry.origin() == origin);
diff --git a/net/http/http_auth_cache.h b/net/http/http_auth_cache.h index 44fda757..bb9b40c 100644 --- a/net/http/http_auth_cache.h +++ b/net/http/http_auth_cache.h
@@ -17,6 +17,7 @@ #include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "net/base/net_export.h" +#include "net/base/network_isolation_key.h" #include "net/http/http_auth.h" #include "url/gurl.h" @@ -121,7 +122,10 @@ enum { kMaxNumPathsPerRealmEntry = 10 }; enum { kMaxNumRealmEntries = 20 }; - HttpAuthCache(); + // If |key_server_entries_by_network_isolation_key| is true, all + // HttpAuth::AUTH_SERVER operations are keyed by NetworkIsolationKey. + // Otherwise, NetworkIsolationKey arguments are ignored. + explicit HttpAuthCache(bool key_server_entries_by_network_isolation_key); ~HttpAuthCache(); // Find the realm entry on server |origin| for realm |realm| and @@ -136,7 +140,8 @@ Entry* Lookup(const GURL& origin, HttpAuth::Target target, const std::string& realm, - HttpAuth::Scheme scheme); + HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key); // Find the entry on server |origin| whose protection space includes // |path|. This uses the assumption in RFC 2617 section 2 that deeper @@ -149,6 +154,7 @@ // returns - the matched entry or nullptr. Entry* LookupByPath(const GURL& origin, HttpAuth::Target target, + const NetworkIsolationKey& network_isolation_key, const std::string& path); // Add an entry on server |origin| for realm |handler->realm()| and @@ -166,6 +172,7 @@ HttpAuth::Target target, const std::string& realm, HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key, const std::string& auth_challenge, const AuthCredentials& credentials, const std::string& path); @@ -181,6 +188,7 @@ HttpAuth::Target target, const std::string& realm, HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key, const AuthCredentials& credentials); // Clears cache entries added since |begin_time| or all entries if @@ -199,9 +207,11 @@ HttpAuth::Target target, const std::string& realm, HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key, const std::string& auth_challenge); - // Copies all entries from |other| cache. + // Copies all entries from |other| cache. Both |this| and |other| must have + // the same key_server_entries_by_network_isolation_key() value. void UpdateAllFrom(const HttpAuthCache& other); size_t GetEntriesSizeForTesting(); @@ -210,15 +220,26 @@ } void set_clock_for_testing(const base::Clock* clock) { clock_ = clock; } + bool key_server_entries_by_network_isolation_key() const { + return key_server_entries_by_network_isolation_key_; + } + private: struct EntryMapKey { - EntryMapKey(const GURL& url, HttpAuth::Target target); + EntryMapKey(const GURL& url, + HttpAuth::Target target, + const NetworkIsolationKey& network_isolation_key, + bool key_server_entries_by_network_isolation_key); ~EntryMapKey(); bool operator<(const EntryMapKey& other) const; GURL url; HttpAuth::Target target; + // Empty if |key_server_entries_by_network_isolation_key| is false, |target| + // is HttpAuth::AUTH_PROXY, or an empty NetworkIsolationKey is passed in to + // the EntryMap constructor. + NetworkIsolationKey network_isolation_key; }; using EntryMap = std::multimap<EntryMapKey, Entry>; @@ -226,12 +247,17 @@ const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance(); const base::Clock* clock_ = base::DefaultClock::GetInstance(); - EntryMap::iterator LookupEntryIt(const GURL& origin, - HttpAuth::Target target, - const std::string& realm, - HttpAuth::Scheme scheme); + EntryMap::iterator LookupEntryIt( + const GURL& origin, + HttpAuth::Target target, + const std::string& realm, + HttpAuth::Scheme scheme, + const NetworkIsolationKey& network_isolation_key); + void EvictLeastRecentlyUsedEntry(); + const bool key_server_entries_by_network_isolation_key_; + EntryMap entries_; DISALLOW_COPY_AND_ASSIGN(HttpAuthCache);
diff --git a/net/http/http_auth_cache_unittest.cc b/net/http/http_auth_cache_unittest.cc index 556bd7c..ec8b31dd 100644 --- a/net/http/http_auth_cache_unittest.cc +++ b/net/http/http_auth_cache_unittest.cc
@@ -11,8 +11,10 @@ #include "base/test/simple_test_clock.h" #include "base/test/simple_test_tick_clock.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/http/http_auth_cache.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/origin.h" using base::ASCIIToUTF16; @@ -46,67 +48,71 @@ TEST(HttpAuthCacheTest, Basic) { GURL origin("http://www.google.com"); GURL origin2("http://www.foobar.com"); - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); HttpAuthCache::Entry* entry; // Add cache entries for 4 realms: "Realm1", "Realm2", "Realm3" and // "Realm4" cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm1", + NetworkIsolationKey(), "Basic realm=Realm1", CreateASCIICredentials("realm1-user", "realm1-password"), "/foo/bar/index.html"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm2", + NetworkIsolationKey(), "Basic realm=Realm2", CreateASCIICredentials("realm2-user", "realm2-password"), "/foo2/index.html"); cache.Add( origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm3", + NetworkIsolationKey(), "Basic realm=Realm3", CreateASCIICredentials("realm3-basic-user", "realm3-basic-password"), std::string()); cache.Add( origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST, - "Digest realm=Realm3", + NetworkIsolationKey(), "Digest realm=Realm3", CreateASCIICredentials("realm3-digest-user", "realm3-digest-password"), "/baz/index.html"); cache.Add( origin, HttpAuth::AUTH_SERVER, kRealm4, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm4", + NetworkIsolationKey(), "Basic realm=Realm4", CreateASCIICredentials("realm4-basic-user", "realm4-basic-password"), "/"); cache.Add(origin2, HttpAuth::AUTH_SERVER, kRealm5, - HttpAuth::AUTH_SCHEME_BASIC, "Basic realm=Realm5", + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "Basic realm=Realm5", CreateASCIICredentials("realm5-user", "realm5-password"), "/"); cache.Add( origin2, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm3", + NetworkIsolationKey(), "Basic realm=Realm3", CreateASCIICredentials("realm3-basic-user", "realm3-basic-password"), std::string()); // There is no Realm5 in origin entry = cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm5, - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_FALSE(entry); // While Realm3 does exist, the origin scheme is wrong. - entry = cache.Lookup(GURL("https://www.google.com"), HttpAuth::AUTH_SERVER, - kRealm3, HttpAuth::AUTH_SCHEME_BASIC); + entry = + cache.Lookup(GURL("https://www.google.com"), HttpAuth::AUTH_SERVER, + kRealm3, HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_FALSE(entry); // Realm, origin scheme ok, authentication scheme wrong entry = cache.Lookup(GURL("http://www.google.com"), HttpAuth::AUTH_SERVER, - kRealm1, HttpAuth::AUTH_SCHEME_DIGEST); + kRealm1, HttpAuth::AUTH_SCHEME_DIGEST, + NetworkIsolationKey()); EXPECT_FALSE(entry); // Valid lookup by origin, realm, scheme. - entry = cache.Lookup(GURL("http://www.google.com:80"), HttpAuth::AUTH_SERVER, - kRealm3, HttpAuth::AUTH_SCHEME_BASIC); + entry = + cache.Lookup(GURL("http://www.google.com:80"), HttpAuth::AUTH_SERVER, + kRealm3, HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme()); EXPECT_EQ(kRealm3, entry->realm()); @@ -118,14 +124,15 @@ // Same realm, scheme with different origins HttpAuthCache::Entry* entry2 = cache.Lookup(GURL("http://www.foobar.com:80"), HttpAuth::AUTH_SERVER, - kRealm3, HttpAuth::AUTH_SCHEME_BASIC); + kRealm3, HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry2); EXPECT_NE(entry, entry2); // Valid lookup by origin, realm, scheme when there's a duplicate // origin, realm in the cache entry = cache.Lookup(GURL("http://www.google.com:80"), HttpAuth::AUTH_SERVER, - kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); + kRealm3, HttpAuth::AUTH_SCHEME_DIGEST, + NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, entry->scheme()); EXPECT_EQ(kRealm3, entry->realm()); @@ -137,7 +144,7 @@ // Valid lookup by realm. entry = cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme()); EXPECT_EQ(kRealm2, entry->realm()); @@ -146,10 +153,12 @@ EXPECT_EQ(ASCIIToUTF16("realm2-password"), entry->credentials().password()); // Check that subpaths are recognized. - HttpAuthCache::Entry* p_realm2_entry = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC); - HttpAuthCache::Entry* p_realm4_entry = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm4, HttpAuth::AUTH_SCHEME_BASIC); + HttpAuthCache::Entry* p_realm2_entry = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); + HttpAuthCache::Entry* p_realm4_entry = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_TRUE(p_realm2_entry); EXPECT_TRUE(p_realm4_entry); HttpAuthCache::Entry realm2_entry = *p_realm2_entry; @@ -157,53 +166,68 @@ // Realm4 applies to '/' and Realm2 applies to '/foo2/'. // LookupByPath() should return the closest enclosing path. // Positive tests: - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/foo2/index.html"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/foo2/index.html"); EXPECT_TRUE(realm2_entry.IsEqualForTesting(*entry)); - entry = - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/foo2/foobar.html"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/foo2/foobar.html"); EXPECT_TRUE(realm2_entry.IsEqualForTesting(*entry)); - entry = - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/foo2/bar/index.html"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/foo2/bar/index.html"); EXPECT_TRUE(realm2_entry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/foo2/"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/foo2/"); EXPECT_TRUE(realm2_entry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/foo2"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/foo2"); EXPECT_TRUE(realm4_entry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/"); EXPECT_TRUE(realm4_entry.IsEqualForTesting(*entry)); // Negative tests: - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/foo3/index.html"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/foo3/index.html"); EXPECT_FALSE(realm2_entry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, std::string()); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), std::string()); EXPECT_FALSE(realm2_entry.IsEqualForTesting(*entry)); // Confirm we find the same realm, different auth scheme by path lookup - HttpAuthCache::Entry* p_realm3_digest_entry = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); + HttpAuthCache::Entry* p_realm3_digest_entry = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey()); EXPECT_TRUE(p_realm3_digest_entry); HttpAuthCache::Entry realm3_digest_entry = *p_realm3_digest_entry; - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/index.html"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/index.html"); EXPECT_TRUE(realm3_digest_entry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/"); EXPECT_TRUE(realm3_digest_entry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz"); EXPECT_FALSE(realm3_digest_entry.IsEqualForTesting(*entry)); // Confirm we find the same realm, different auth scheme by path lookup - HttpAuthCache::Entry* p_realm3DigestEntry = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); + HttpAuthCache::Entry* p_realm3DigestEntry = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey()); EXPECT_TRUE(p_realm3DigestEntry); HttpAuthCache::Entry realm3DigestEntry = *p_realm3DigestEntry; - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/index.html"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/index.html"); EXPECT_TRUE(realm3DigestEntry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/"); EXPECT_TRUE(realm3DigestEntry.IsEqualForTesting(*entry)); - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz"); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz"); EXPECT_FALSE(realm3DigestEntry.IsEqualForTesting(*entry)); // Lookup using empty path (may be used for proxy). - entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, std::string()); + entry = cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), std::string()); EXPECT_TRUE(entry); EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme()); EXPECT_EQ(kRealm3, entry->realm()); @@ -219,73 +243,258 @@ const char kServerPath[] = "/foo/bar/index.html"; GURL origin("http://www.google.com"); - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); HttpAuthCache::Entry* entry; // Add AUTH_SERVER entry. cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm1", AuthCredentials(kServerUser, kServerPass), - kServerPath); + NetworkIsolationKey(), "Basic realm=Realm1", + AuthCredentials(kServerUser, kServerPass), kServerPath); // Make sure credentials are only accessible with AUTH_SERVER target. entry = cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(entry->credentials().username(), kServerUser); EXPECT_EQ(entry->credentials().password(), kServerPass); - EXPECT_EQ(entry, - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, kServerPath)); + EXPECT_EQ(entry, cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), kServerPath)); EXPECT_FALSE(cache.Lookup(origin, HttpAuth::AUTH_PROXY, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, kServerPath)); + HttpAuth::AUTH_SCHEME_BASIC, + NetworkIsolationKey())); + EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, + NetworkIsolationKey(), kServerPath)); // Add AUTH_PROXY entry with same origin and realm but different credentials. cache.Add(origin, HttpAuth::AUTH_PROXY, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=Realm1", AuthCredentials(kProxyUser, kProxyPass), "/"); + NetworkIsolationKey(), "Basic realm=Realm1", + AuthCredentials(kProxyUser, kProxyPass), "/"); // Make sure credentials are only accessible with the corresponding target. entry = cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(entry->credentials().username(), kServerUser); EXPECT_EQ(entry->credentials().password(), kServerPass); - EXPECT_EQ(entry, - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, kServerPath)); + EXPECT_EQ(entry, cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), kServerPath)); entry = cache.Lookup(origin, HttpAuth::AUTH_PROXY, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(entry->credentials().username(), kProxyUser); EXPECT_EQ(entry->credentials().password(), kProxyPass); - EXPECT_EQ(entry, cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, "/")); + EXPECT_EQ(entry, cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, + NetworkIsolationKey(), "/")); // Remove the AUTH_SERVER entry. EXPECT_TRUE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kServerUser, kServerPass))); // Verify that only the AUTH_SERVER entry was removed. EXPECT_FALSE(cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, kServerPath)); + HttpAuth::AUTH_SCHEME_BASIC, + NetworkIsolationKey())); + EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), kServerPath)); entry = cache.Lookup(origin, HttpAuth::AUTH_PROXY, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(entry->credentials().username(), kProxyUser); EXPECT_EQ(entry->credentials().password(), kProxyPass); - EXPECT_EQ(entry, cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, "/")); + EXPECT_EQ(entry, cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, + NetworkIsolationKey(), "/")); // Remove the AUTH_PROXY entry. EXPECT_TRUE(cache.Remove(origin, HttpAuth::AUTH_PROXY, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kProxyUser, kProxyPass))); // Verify that neither entry remains. EXPECT_FALSE(cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, kServerPath)); + HttpAuth::AUTH_SCHEME_BASIC, + NetworkIsolationKey())); + EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), kServerPath)); EXPECT_FALSE(cache.Lookup(origin, HttpAuth::AUTH_PROXY, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, "/")); + HttpAuth::AUTH_SCHEME_BASIC, + NetworkIsolationKey())); + EXPECT_FALSE(cache.LookupByPath(origin, HttpAuth::AUTH_PROXY, + NetworkIsolationKey(), "/")); +} + +// Make sure server credentials with different NetworkIsolationKeys are treated +// separately if |key_entries_by_network_isolation_key| is set to true. +TEST(HttpAuthCacheTest, SeparateServersByNetworkIsolationKey) { + const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1); + const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2); + + GURL kPseudoOrigin("http://www.google.com"); + const char kPath[] = "/"; + + const base::string16 kUser1 = ASCIIToUTF16("user1"); + const base::string16 kPass1 = ASCIIToUTF16("pass1"); + const base::string16 kUser2 = ASCIIToUTF16("user2"); + const base::string16 kPass2 = ASCIIToUTF16("pass2"); + + for (bool key_entries_by_network_isolation_key : {false, true}) { + HttpAuthCache cache(key_entries_by_network_isolation_key); + HttpAuthCache::Entry* entry; + + // Add entry for kNetworkIsolationKey1. + cache.Add(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1, + "Basic realm=Realm1", AuthCredentials(kUser1, kPass1), kPath); + + entry = cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + EXPECT_EQ(entry->credentials().username(), kUser1); + EXPECT_EQ(entry->credentials().password(), kPass1); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey1, kPath)); + if (key_entries_by_network_isolation_key) { + EXPECT_FALSE(cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, + kNetworkIsolationKey2)); + EXPECT_FALSE(cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey2, kPath)); + } else { + EXPECT_EQ(entry, cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kRealm1, HttpAuth::AUTH_SCHEME_BASIC, + kNetworkIsolationKey2)); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey2, kPath)); + } + + // Add entry for kNetworkIsolationKey2. + cache.Add(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2, + "Basic realm=Realm1", AuthCredentials(kUser2, kPass2), kPath); + + entry = cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2); + ASSERT_TRUE(entry); + EXPECT_EQ(entry->credentials().username(), kUser2); + EXPECT_EQ(entry->credentials().password(), kPass2); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey2, kPath)); + entry = cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey1, kPath)); + if (key_entries_by_network_isolation_key) { + EXPECT_EQ(entry->credentials().username(), kUser1); + EXPECT_EQ(entry->credentials().password(), kPass1); + } else { + EXPECT_EQ(entry->credentials().username(), kUser2); + EXPECT_EQ(entry->credentials().password(), kPass2); + } + + // Remove the entry that was just added. + EXPECT_TRUE(cache.Remove(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2, + AuthCredentials(kUser2, kPass2))); + + EXPECT_FALSE(cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, + kNetworkIsolationKey2)); + EXPECT_FALSE(cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey2, kPath)); + if (key_entries_by_network_isolation_key) { + entry = cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + EXPECT_EQ(entry->credentials().username(), kUser1); + EXPECT_EQ(entry->credentials().password(), kPass1); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey1, kPath)); + } else { + EXPECT_FALSE(cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, + kNetworkIsolationKey1)); + EXPECT_FALSE(cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_SERVER, + kNetworkIsolationKey1, kPath)); + } + } +} + +// Make sure added proxy credentials ignore NetworkIsolationKey, even if if +// |key_entries_by_network_isolation_key| is set to true. +TEST(HttpAuthCacheTest, NeverSeparateProxiesByNetworkIsolationKey) { + const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1); + const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2); + + GURL kPseudoOrigin("http://www.google.com"); + const char kPath[] = "/"; + + const base::string16 kUser1 = ASCIIToUTF16("user1"); + const base::string16 kPass1 = ASCIIToUTF16("pass1"); + const base::string16 kUser2 = ASCIIToUTF16("user2"); + const base::string16 kPass2 = ASCIIToUTF16("pass2"); + + for (bool key_entries_by_network_isolation_key : {false, true}) { + HttpAuthCache cache(key_entries_by_network_isolation_key); + HttpAuthCache::Entry* entry; + + // Add entry for kNetworkIsolationKey1. + cache.Add(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1, + "Basic realm=Realm1", AuthCredentials(kUser1, kPass1), kPath); + + entry = cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + EXPECT_EQ(entry->credentials().username(), kUser1); + EXPECT_EQ(entry->credentials().password(), kPass1); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_PROXY, + kNetworkIsolationKey1, kPath)); + EXPECT_EQ(entry, + cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_PROXY, + kNetworkIsolationKey2, kPath)); + + // Add entry for kNetworkIsolationKey2. It should overwrite the entry for + // kNetworkIsolationKey1. + cache.Add(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2, + "Basic realm=Realm1", AuthCredentials(kUser2, kPass2), kPath); + + entry = cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2); + ASSERT_TRUE(entry); + EXPECT_EQ(entry->credentials().username(), kUser2); + EXPECT_EQ(entry->credentials().password(), kPass2); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_PROXY, + kNetworkIsolationKey2, kPath)); + EXPECT_EQ(entry, + cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1)); + EXPECT_EQ(entry, cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_PROXY, + kNetworkIsolationKey1, kPath)); + + // Remove the entry that was just added using an empty NetworkIsolationKey. + EXPECT_TRUE(cache.Remove(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + AuthCredentials(kUser2, kPass2))); + + EXPECT_FALSE(cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, + kNetworkIsolationKey2)); + EXPECT_FALSE(cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_PROXY, + kNetworkIsolationKey2, kPath)); + EXPECT_FALSE(cache.Lookup(kPseudoOrigin, HttpAuth::AUTH_PROXY, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, + kNetworkIsolationKey1)); + EXPECT_FALSE(cache.LookupByPath(kPseudoOrigin, HttpAuth::AUTH_PROXY, + kNetworkIsolationKey1, kPath)); + } } TEST(HttpAuthCacheTest, AddPath) { @@ -323,23 +532,25 @@ // Calling Add when the realm entry already exists, should append that // path. TEST(HttpAuthCacheTest, AddToExistingEntry) { - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); GURL origin("http://www.foobar.com:70"); const std::string kAuthChallenge = "Basic realm=MyRealm"; const std::string kRealm = "MyRealm"; HttpAuthCache::Entry* orig_entry = cache.Add( origin, HttpAuth::AUTH_SERVER, kRealm, HttpAuth::AUTH_SCHEME_BASIC, - kAuthChallenge, CreateASCIICredentials("user1", "password1"), "/x/y/z/"); + NetworkIsolationKey(), kAuthChallenge, + CreateASCIICredentials("user1", "password1"), "/x/y/z/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm, HttpAuth::AUTH_SCHEME_BASIC, - kAuthChallenge, CreateASCIICredentials("user2", "password2"), - "/z/y/x/"); + NetworkIsolationKey(), kAuthChallenge, + CreateASCIICredentials("user2", "password2"), "/z/y/x/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm, HttpAuth::AUTH_SCHEME_BASIC, - kAuthChallenge, CreateASCIICredentials("user3", "password3"), - "/z/y"); + NetworkIsolationKey(), kAuthChallenge, + CreateASCIICredentials("user3", "password3"), "/z/y"); - HttpAuthCache::Entry* entry = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm, HttpAuth::AUTH_SCHEME_BASIC); + HttpAuthCache::Entry* entry = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_TRUE(entry == orig_entry); EXPECT_EQ(ASCIIToUTF16("user3"), entry->credentials().username()); @@ -353,70 +564,74 @@ TEST(HttpAuthCacheTest, Remove) { GURL origin("http://foobar2.com"); - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm1", AuthCredentials(kAlice, k123), "/"); + NetworkIsolationKey(), "basic realm=Realm1", + AuthCredentials(kAlice, k123), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", CreateASCIICredentials("bob", "princess"), - "/"); + NetworkIsolationKey(), "basic realm=Realm2", + CreateASCIICredentials("bob", "princess"), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm3", AuthCredentials(kAdmin, kPassword), "/"); + NetworkIsolationKey(), "basic realm=Realm3", + AuthCredentials(kAdmin, kPassword), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST, "digest realm=Realm3", - AuthCredentials(kRoot, kWileCoyote), "/"); + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), + "digest realm=Realm3", AuthCredentials(kRoot, kWileCoyote), "/"); // Fails, because there is no realm "Realm5". EXPECT_FALSE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm5, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kAlice, k123))); // Fails because the origin is wrong. - EXPECT_FALSE(cache.Remove( - GURL("http://foobar2.com:100"), HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, AuthCredentials(kAlice, k123))); + EXPECT_FALSE(cache.Remove(GURL("http://foobar2.com:100"), + HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + AuthCredentials(kAlice, k123))); // Fails because the username is wrong. EXPECT_FALSE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kAlice2, k123))); // Fails because the password is wrong. EXPECT_FALSE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kAlice, k1234))); // Fails because the authentication type is wrong. EXPECT_FALSE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_DIGEST, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), AuthCredentials(kAlice, k123))); // Succeeds. EXPECT_TRUE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kAlice, k123))); // Fails because we just deleted the entry! EXPECT_FALSE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kAlice, k123))); // Succeed when there are two authentication types for the same origin,realm. EXPECT_TRUE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), AuthCredentials(kRoot, kWileCoyote))); // Succeed as above, but when entries were added in opposite order cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST, "digest realm=Realm3", - AuthCredentials(kRoot, kWileCoyote), "/"); + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), + "digest realm=Realm3", AuthCredentials(kRoot, kWileCoyote), "/"); EXPECT_TRUE(cache.Remove(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_BASIC, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), AuthCredentials(kAdmin, kPassword))); // Make sure that removing one entry still leaves the other available for // lookup. - HttpAuthCache::Entry* entry = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); + HttpAuthCache::Entry* entry = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey()); EXPECT_FALSE(nullptr == entry); } @@ -428,50 +643,61 @@ base::SimpleTestClock test_clock; test_clock.SetNow(start_time); - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); cache.set_clock_for_testing(&test_clock); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm1", AuthCredentials(kAlice, k123), "/"); + NetworkIsolationKey(), "basic realm=Realm1", + AuthCredentials(kAlice, k123), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", AuthCredentials(kRoot, kWileCoyote), "/"); + NetworkIsolationKey(), "basic realm=Realm2", + AuthCredentials(kRoot, kWileCoyote), "/"); test_clock.Advance(base::TimeDelta::FromSeconds(10)); // Time now 12:00:10 cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm3", AuthCredentials(kAlice2, k1234), "/"); + NetworkIsolationKey(), "basic realm=Realm3", + AuthCredentials(kAlice2, k1234), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm4, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm4", AuthCredentials(kUsername, kPassword), "/"); + NetworkIsolationKey(), "basic realm=Realm4", + AuthCredentials(kUsername, kPassword), "/"); // Add path to existing entry. cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", AuthCredentials(kAdmin, kPassword), "/baz/"); + NetworkIsolationKey(), "basic realm=Realm2", + AuthCredentials(kAdmin, kPassword), "/baz/"); base::Time test_time; ASSERT_TRUE(base::Time::FromString("30 May 2018 12:00:05", &test_time)); cache.ClearEntriesAddedSince(test_time); // Realms 1 and 2 are older than 12:00:05 and should not be cleared - EXPECT_NE(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_NE(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC)); + EXPECT_NE(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_NE(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); // Creation time is set for a whole entry rather than for a particular path. // Path added within the requested duration isn't be removed. - EXPECT_NE(nullptr, - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/")); + EXPECT_NE(nullptr, cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/")); // Realms 3 and 4 are newer than 12:00:05 and should be cleared. - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, - HttpAuth::AUTH_SCHEME_BASIC)); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); cache.ClearEntriesAddedSince(start_time - base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC)); EXPECT_EQ(nullptr, - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/")); + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/")); } TEST(HttpAuthCacheTest, ClearEntriesAddedSinceWithNullTime) { @@ -480,36 +706,45 @@ base::SimpleTestClock test_clock; test_clock.SetNow(base::Time::Now()); - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); cache.set_clock_for_testing(&test_clock); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm1", AuthCredentials(kAlice, k123), "/"); + NetworkIsolationKey(), "basic realm=Realm1", + AuthCredentials(kAlice, k123), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", AuthCredentials(kRoot, kWileCoyote), "/"); + NetworkIsolationKey(), "basic realm=Realm2", + AuthCredentials(kRoot, kWileCoyote), "/"); test_clock.Advance(base::TimeDelta::FromSeconds(10)); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm3", AuthCredentials(kAlice2, k1234), "/"); + NetworkIsolationKey(), "basic realm=Realm3", + AuthCredentials(kAlice2, k1234), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm4, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm4", AuthCredentials(kUsername, kPassword), "/"); + NetworkIsolationKey(), "basic realm=Realm4", + AuthCredentials(kUsername, kPassword), "/"); // Add path to existing entry. cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", AuthCredentials(kAdmin, kPassword), "/baz/"); + NetworkIsolationKey(), "basic realm=Realm2", + AuthCredentials(kAdmin, kPassword), "/baz/"); cache.ClearEntriesAddedSince(base::Time()); // All entries should be cleared. - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC)); EXPECT_EQ(nullptr, - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/")); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, - HttpAuth::AUTH_SCHEME_BASIC)); + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/")); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); } TEST(HttpAuthCacheTest, ClearAllEntries) { @@ -518,44 +753,54 @@ base::SimpleTestClock test_clock; test_clock.SetNow(base::Time::Now()); - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); cache.set_clock_for_testing(&test_clock); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm1", AuthCredentials(kAlice, k123), "/"); + NetworkIsolationKey(), "basic realm=Realm1", + AuthCredentials(kAlice, k123), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", AuthCredentials(kRoot, kWileCoyote), "/"); + NetworkIsolationKey(), "basic realm=Realm2", + AuthCredentials(kRoot, kWileCoyote), "/"); test_clock.Advance(base::TimeDelta::FromSeconds(10)); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm3", AuthCredentials(kAlice2, k1234), "/"); + NetworkIsolationKey(), "basic realm=Realm3", + AuthCredentials(kAlice2, k1234), "/"); cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm4, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm4", AuthCredentials(kUsername, kPassword), "/"); + NetworkIsolationKey(), "basic realm=Realm4", + AuthCredentials(kUsername, kPassword), "/"); // Add path to existing entry. cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, - "basic realm=Realm2", AuthCredentials(kAdmin, kPassword), "/baz/"); + NetworkIsolationKey(), "basic realm=Realm2", + AuthCredentials(kAdmin, kPassword), "/baz/"); test_clock.Advance(base::TimeDelta::FromSeconds(55)); cache.ClearAllEntries(); // All entries should be cleared. - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC)); EXPECT_EQ(nullptr, - cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, "/baz/")); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_BASIC)); - EXPECT_EQ(nullptr, cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, - HttpAuth::AUTH_SCHEME_BASIC)); + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), "/baz/")); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); + EXPECT_EQ(nullptr, + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey())); } TEST(HttpAuthCacheTest, UpdateStaleChallenge) { - HttpAuthCache cache; + HttpAuthCache cache(false /* key_entries_by_network_isolation_key */); GURL origin("http://foobar2.com"); HttpAuthCache::Entry* entry_pre = cache.Add( origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_DIGEST, + NetworkIsolationKey(), "Digest realm=Realm1," "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\"", CreateASCIICredentials("realm-digest-user", "realm-digest-password"), @@ -568,6 +813,7 @@ bool update_success = cache.UpdateStaleChallenge( origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_DIGEST, + NetworkIsolationKey(), "Digest realm=Realm1," "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\"," "stale=\"true\""); @@ -575,14 +821,16 @@ // After the stale update, the entry should still exist in the cache and // the nonce count should be reset to 0. - HttpAuthCache::Entry* entry_post = cache.Lookup( - origin, HttpAuth::AUTH_SERVER, kRealm1, HttpAuth::AUTH_SCHEME_DIGEST); + HttpAuthCache::Entry* entry_post = + cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey()); ASSERT_TRUE(entry_post != nullptr); EXPECT_EQ(2, entry_post->IncrementNonceCount()); // UpdateStaleChallenge will fail if an entry doesn't exist in the cache. bool update_failure = cache.UpdateStaleChallenge( origin, HttpAuth::AUTH_SERVER, kRealm2, HttpAuth::AUTH_SCHEME_DIGEST, + NetworkIsolationKey(), "Digest realm=Realm2," "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\"," "stale=\"true\""); @@ -594,53 +842,61 @@ std::string path("/some/path"); std::string another_path("/another/path"); - HttpAuthCache first_cache; + HttpAuthCache first_cache(false /* key_entries_by_network_isolation_key */); + ; HttpAuthCache::Entry* entry; first_cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm1", - AuthCredentials(kAlice, k123), path); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "basic realm=Realm1", AuthCredentials(kAlice, k123), path); first_cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm2", - AuthCredentials(kAlice2, k1234), path); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "basic realm=Realm2", AuthCredentials(kAlice2, k1234), path); first_cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST, "digest realm=Realm3", - AuthCredentials(kRoot, kWileCoyote), path); + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), + "digest realm=Realm3", AuthCredentials(kRoot, kWileCoyote), + path); entry = first_cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST, "digest realm=Realm3", + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), + "digest realm=Realm3", AuthCredentials(kRoot, kWileCoyote), another_path); EXPECT_EQ(2, entry->IncrementNonceCount()); - HttpAuthCache second_cache; + HttpAuthCache second_cache(false /* key_entries_by_network_isolation_key */); + ; // Will be overwritten by kRoot:kWileCoyote. second_cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST, "digest realm=Realm3", - AuthCredentials(kAlice2, k1234), path); + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey(), + "digest realm=Realm3", AuthCredentials(kAlice2, k1234), + path); // Should be left intact. second_cache.Add(origin, HttpAuth::AUTH_SERVER, kRealm4, - HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm4", - AuthCredentials(kAdmin, kRoot), path); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "basic realm=Realm4", AuthCredentials(kAdmin, kRoot), path); second_cache.UpdateAllFrom(first_cache); // Copied from first_cache. - entry = second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, - HttpAuth::AUTH_SCHEME_BASIC); + entry = + second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm1, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_TRUE(nullptr != entry); EXPECT_EQ(kAlice, entry->credentials().username()); EXPECT_EQ(k123, entry->credentials().password()); // Copied from first_cache. - entry = second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, - HttpAuth::AUTH_SCHEME_BASIC); + entry = + second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm2, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_TRUE(nullptr != entry); EXPECT_EQ(kAlice2, entry->credentials().username()); EXPECT_EQ(k1234, entry->credentials().password()); // Overwritten from first_cache. - entry = second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, - HttpAuth::AUTH_SCHEME_DIGEST); + entry = + second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm3, + HttpAuth::AUTH_SCHEME_DIGEST, NetworkIsolationKey()); EXPECT_TRUE(nullptr != entry); EXPECT_EQ(kRoot, entry->credentials().username()); EXPECT_EQ(kWileCoyote, entry->credentials().password()); @@ -648,15 +904,16 @@ EXPECT_EQ(3, entry->IncrementNonceCount()); // All paths should get copied. - entry = - second_cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, another_path); + entry = second_cache.LookupByPath(origin, HttpAuth::AUTH_SERVER, + NetworkIsolationKey(), another_path); EXPECT_TRUE(nullptr != entry); EXPECT_EQ(kRoot, entry->credentials().username()); EXPECT_EQ(kWileCoyote, entry->credentials().password()); // Left intact in second_cache. - entry = second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, - HttpAuth::AUTH_SCHEME_BASIC); + entry = + second_cache.Lookup(origin, HttpAuth::AUTH_SERVER, kRealm4, + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); EXPECT_TRUE(nullptr != entry); EXPECT_EQ(kAdmin, entry->credentials().username()); EXPECT_EQ(kRoot, entry->credentials().password()); @@ -666,7 +923,9 @@ // insertion and existence testing). class HttpAuthCacheEvictionTest : public testing::Test { protected: - HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { } + HttpAuthCacheEvictionTest() + : origin_("http://www.google.com"), + cache_(false /* key_entries_by_network_isolation_key */) {} std::string GenerateRealm(int realm_i) { return base::StringPrintf("Realm %d", realm_i); @@ -682,15 +941,15 @@ void AddPathToRealm(int realm_i, int path_i) { cache_.Add(origin_, HttpAuth::AUTH_SERVER, GenerateRealm(realm_i), - HttpAuth::AUTH_SCHEME_BASIC, std::string(), - AuthCredentials(kUsername, kPassword), + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + std::string(), AuthCredentials(kUsername, kPassword), GeneratePath(realm_i, path_i)); } void CheckRealmExistence(int realm_i, bool exists) { const HttpAuthCache::Entry* entry = cache_.Lookup(origin_, HttpAuth::AUTH_SERVER, GenerateRealm(realm_i), - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); if (exists) { EXPECT_FALSE(entry == nullptr); EXPECT_EQ(GenerateRealm(realm_i), entry->realm()); @@ -701,7 +960,8 @@ void CheckPathExistence(int realm_i, int path_i, bool exists) { const HttpAuthCache::Entry* entry = cache_.LookupByPath( - origin_, HttpAuth::AUTH_SERVER, GeneratePath(realm_i, path_i)); + origin_, HttpAuth::AUTH_SERVER, NetworkIsolationKey(), + GeneratePath(realm_i, path_i)); if (exists) { EXPECT_FALSE(entry == nullptr); EXPECT_EQ(GenerateRealm(realm_i), entry->realm());
diff --git a/net/http/http_auth_controller.cc b/net/http/http_auth_controller.cc index acc47768..0e11a5d 100644 --- a/net/http/http_auth_controller.cc +++ b/net/http/http_auth_controller.cc
@@ -139,6 +139,7 @@ HttpAuthController::HttpAuthController( HttpAuth::Target target, const GURL& auth_url, + const NetworkIsolationKey& network_isolation_key, HttpAuthCache* http_auth_cache, HttpAuthHandlerFactory* http_auth_handler_factory, HostResolver* host_resolver, @@ -147,6 +148,7 @@ auth_url_(auth_url), auth_origin_(auth_url.GetOrigin()), auth_path_(auth_url.path()), + network_isolation_key_(network_isolation_key), embedded_identity_used_(false), allow_default_credentials_(allow_default_credentials), default_credentials_used_(false), @@ -220,8 +222,8 @@ // is expected to be fast. LookupByPath() is fast in the common case, since // the number of http auth cache entries is expected to be very small. // (For most users in fact, it will be 0.) - HttpAuthCache::Entry* entry = - http_auth_cache_->LookupByPath(auth_origin_, target_, auth_path_); + HttpAuthCache::Entry* entry = http_auth_cache_->LookupByPath( + auth_origin_, target_, network_isolation_key_, auth_path_); if (!entry) return false; @@ -294,7 +296,8 @@ case HttpAuth::AUTHORIZATION_RESULT_STALE: if (http_auth_cache_->UpdateStaleChallenge( auth_origin_, target_, handler_->realm(), - handler_->auth_scheme(), challenge_used)) { + handler_->auth_scheme(), network_isolation_key_, + challenge_used)) { InvalidateCurrentHandler(INVALIDATE_HANDLER); } else { // It's possible that a server could incorrectly issue a stale @@ -420,8 +423,9 @@ break; default: http_auth_cache_->Add(auth_origin_, target_, handler_->realm(), - handler_->auth_scheme(), handler_->challenge(), - identity_.credentials, auth_path_); + handler_->auth_scheme(), network_isolation_key_, + handler_->challenge(), identity_.credentials, + auth_path_); break; } } @@ -469,7 +473,8 @@ // Note: we require the credentials to match before invalidating // since the entry in the cache may be newer than what we used last time. http_auth_cache_->Remove(auth_origin_, target_, handler_->realm(), - handler_->auth_scheme(), identity_.credentials); + handler_->auth_scheme(), network_isolation_key_, + identity_.credentials); } void HttpAuthController::PrepareIdentityForReuse() { @@ -518,8 +523,9 @@ } // Check the auth cache for a realm entry. - HttpAuthCache::Entry* entry = http_auth_cache_->Lookup( - auth_origin_, target_, handler_->realm(), handler_->auth_scheme()); + HttpAuthCache::Entry* entry = + http_auth_cache_->Lookup(auth_origin_, target_, handler_->realm(), + handler_->auth_scheme(), network_isolation_key_); if (entry) { identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
diff --git a/net/http/http_auth_controller.h b/net/http/http_auth_controller.h index 414554f..27a78f2 100644 --- a/net/http/http_auth_controller.h +++ b/net/http/http_auth_controller.h
@@ -14,6 +14,7 @@ #include "base/threading/thread_checker.h" #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" +#include "net/base/network_isolation_key.h" #include "net/http/http_auth.h" #include "net/http/http_auth_preferences.h" #include "net/log/net_log_with_source.h" @@ -59,6 +60,10 @@ // If |target| is PROXY, then |auth_url| should have no hierarchical // part since that is meaningless. // + // * |network_isolation_key| specifies the NetworkIsolationKey associated with + // the resource load. Depending on settings, credentials may be scoped + // to a single NetworkIsolationKey. + // // * |http_auth_cache| specifies the credentials cache to use. During // authentication if explicit (user-provided) credentials are used and // they can be cached to respond to authentication challenges in the @@ -81,6 +86,7 @@ HttpAuthController( HttpAuth::Target target, const GURL& auth_url, + const NetworkIsolationKey& network_isolation_key, HttpAuthCache* http_auth_cache, HttpAuthHandlerFactory* http_auth_handler_factory, HostResolver* host_resolver, @@ -197,6 +203,9 @@ // For proxy authentication the path is empty. const std::string auth_path_; + // NetworkIsolationKey assocaied with the request. + const NetworkIsolationKey network_isolation_key_; + // |handler_| encapsulates the logic for the particular auth-scheme. // This includes the challenge's parameters. If nullptr, then there is no // associated auth handler.
diff --git a/net/http/http_auth_controller_unittest.cc b/net/http/http_auth_controller_unittest.cc index 7e654baa..d05f247 100644 --- a/net/http/http_auth_controller_unittest.cc +++ b/net/http/http_auth_controller_unittest.cc
@@ -56,7 +56,8 @@ int expected_controller_rv, SchemeState scheme_state, const NetLogWithSource& net_log = NetLogWithSource()) { - HttpAuthCache dummy_auth_cache; + HttpAuthCache dummy_auth_cache( + false /* key_server_entries_by_network_isolation_key */); HttpRequestInfo request; request.method = "GET"; @@ -75,10 +76,11 @@ auth_handler_factory.set_do_init_from_challenge(true); auto host_resolver = std::make_unique<MockHostResolver>(); - scoped_refptr<HttpAuthController> controller(new HttpAuthController( - HttpAuth::AUTH_PROXY, GURL("http://example.com"), &dummy_auth_cache, - &auth_handler_factory, host_resolver.get(), - HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); + scoped_refptr<HttpAuthController> controller( + base::MakeRefCounted<HttpAuthController>( + HttpAuth::AUTH_PROXY, GURL("http://example.com"), + NetworkIsolationKey(), &dummy_auth_cache, &auth_handler_factory, + host_resolver.get(), HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); SSLInfo null_ssl_info; ASSERT_EQ(OK, controller->HandleAuthChallenge(headers, null_ssl_info, false, false, net_log)); @@ -213,7 +215,8 @@ }; NetLogWithSource dummy_log; - HttpAuthCache dummy_auth_cache; + HttpAuthCache dummy_auth_cache( + false /* key_server_entries_by_network_isolation_key */); HttpRequestInfo request; request.method = "GET"; request.url = GURL("http://example.com"); @@ -258,10 +261,11 @@ auto host_resolver = std::make_unique<MockHostResolver>(); - scoped_refptr<HttpAuthController> controller(new HttpAuthController( - HttpAuth::AUTH_SERVER, GURL("http://example.com"), &dummy_auth_cache, - &auth_handler_factory, host_resolver.get(), - HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); + scoped_refptr<HttpAuthController> controller( + base::MakeRefCounted<HttpAuthController>( + HttpAuth::AUTH_SERVER, GURL("http://example.com"), + NetworkIsolationKey(), &dummy_auth_cache, &auth_handler_factory, + host_resolver.get(), HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); SSLInfo null_ssl_info; ASSERT_EQ(OK, controller->HandleAuthChallenge(headers, null_ssl_info, false, false, dummy_log));
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index 6fca8117..4da166c4 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -89,7 +89,8 @@ enable_quic_proxies_for_https_urls(false), disable_idle_sockets_close_on_memory_pressure(false), allow_default_credentials(HttpAuthPreferences::DefaultCredentials:: - DISALLOW_DEFAULT_CREDENTIALS) { + DISALLOW_DEFAULT_CREDENTIALS), + key_auth_cache_server_entries_by_network_isolation_key(false) { enable_early_data = base::FeatureList::IsEnabled(features::kEnableTLS13EarlyData); } @@ -141,6 +142,8 @@ #endif proxy_resolution_service_(context.proxy_resolution_service), ssl_config_service_(context.ssl_config_service), + http_auth_cache_( + params.key_auth_cache_server_entries_by_network_isolation_key), ssl_client_session_cache_(SSLClientSessionCache::Config()), ssl_client_context_(context.ssl_config_service, context.cert_verifier,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index f6a0a95b..037b629 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -150,6 +150,8 @@ // If authentication APIs that support ambient authentication are allowed // to use the default credentials. HttpAuthPreferences::DefaultCredentials allow_default_credentials; + + bool key_auth_cache_server_entries_by_network_isolation_key; }; // Structure with pointers to the dependencies of the HttpNetworkSession.
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 66c4164..a1787e4 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -883,9 +883,10 @@ return OK; HttpAuth::Target target = HttpAuth::AUTH_PROXY; if (!auth_controllers_[target].get()) - auth_controllers_[target] = new HttpAuthController( - target, AuthURL(target), session_->http_auth_cache(), - session_->http_auth_handler_factory(), session_->host_resolver(), + auth_controllers_[target] = base::MakeRefCounted<HttpAuthController>( + target, AuthURL(target), request_->network_isolation_key, + session_->http_auth_cache(), session_->http_auth_handler_factory(), + session_->host_resolver(), session_->params().allow_default_credentials); return auth_controllers_[target]->MaybeGenerateAuthToken(request_, io_callback_, @@ -903,9 +904,10 @@ next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE; HttpAuth::Target target = HttpAuth::AUTH_SERVER; if (!auth_controllers_[target].get()) { - auth_controllers_[target] = new HttpAuthController( - target, AuthURL(target), session_->http_auth_cache(), - session_->http_auth_handler_factory(), session_->host_resolver(), + auth_controllers_[target] = base::MakeRefCounted<HttpAuthController>( + target, AuthURL(target), request_->network_isolation_key, + session_->http_auth_cache(), session_->http_auth_handler_factory(), + session_->host_resolver(), session_->params().allow_default_credentials); if (request_->load_flags & LOAD_DO_NOT_USE_EMBEDDED_IDENTITY) auth_controllers_[target]->DisableEmbeddedIdentity();
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index a7fd28ec..4db22adf 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -3341,7 +3341,7 @@ // Check that credentials were successfully cached, with the right target. HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup( GURL("http://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); ASSERT_EQ(kFoo, entry->credentials().username()); ASSERT_EQ(kBar, entry->credentials().password()); @@ -4005,13 +4005,13 @@ MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" "Host: myproxy:70\r\n" "Proxy-Connection: keep-alive\r\n\r\n"), - // Rety with proxy auth credentials, which will result in a server auth + // Retry with proxy auth credentials, which will result in a server auth // challenge. MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" "Host: myproxy:70\r\n" "Proxy-Connection: keep-alive\r\n" "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - // Rety with proxy and server auth credentials, which gets a response. + // Retry with proxy and server auth credentials, which gets a response. MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" "Host: myproxy:70\r\n" "Proxy-Connection: keep-alive\r\n" @@ -4091,13 +4091,13 @@ // Check that the credentials were cached correctly. HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup( GURL("http://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); ASSERT_EQ(kFoo, entry->credentials().username()); ASSERT_EQ(kBar, entry->credentials().password()); - entry = session->http_auth_cache()->Lookup(GURL("http://myproxy:70"), - HttpAuth::AUTH_SERVER, "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC); + entry = session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey()); ASSERT_TRUE(entry); ASSERT_EQ(kFoo2, entry->credentials().username()); ASSERT_EQ(kBar2, entry->credentials().password()); @@ -4121,6 +4121,538 @@ session->CloseAllConnections(); } +// Test the no-tunnel HTTP auth case where proxy and server origins and realms +// are the same, but the user/passwords are different, and with different +// NetworkIsolationKeys. Sends one request with a NIK, response to both proxy +// and auth challenges, sends another request with another NIK, expecting only +// the proxy credentials to be cached, and thus sees only a server auth +// challenge. Then sends a request with the original NIK, expecting cached proxy +// and auth credentials that match the ones used in the first request. +// +// Serves to verify credentials are correctly separated based on +// HttpAuth::Target and NetworkIsolationKeys, but NetworkIsolationKey only +// affects server credentials, not proxy credentials. +TEST_F(HttpNetworkTransactionTest, + BasicAuthProxyMatchesServerAuthWithNetworkIsolationKeyNoTunnel) { + const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1); + const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2); + + // This test would need to use a single socket without this option enabled. + // Best to use this option when it would affect a test, as it will eventually + // become the default behavior. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kPartitionConnectionsByNetworkIsolationKey); + + // Proxy matches request URL. + session_deps_.proxy_resolution_service = + ProxyResolutionService::CreateFixedFromPacResult( + "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS); + BoundTestNetLog log; + session_deps_.net_log = log.bound().net_log(); + session_deps_.key_auth_cache_server_entries_by_network_isolation_key = true; + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + MockWrite data_writes[] = { + // Initial request gets a proxy auth challenge. + MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + // Retry with proxy auth credentials, which will result in a server auth + // challenge. + MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + // Retry with proxy and server auth credentials, which gets a response. + MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" + "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), + // Another request to the same server and using the same NIK should + // preemptively send the correct cached proxy and server + // auth headers. + MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" + "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), + }; + + MockRead data_reads[] = { + // Proxy auth challenge. + MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"), + // Server auth challenge. + MockRead("HTTP/1.0 401 Authentication Required\r\n" + "Proxy-Connection: keep-alive\r\n" + "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"), + // Response. + MockRead("HTTP/1.1 200 OK\r\n" + "Proxy-Connection: keep-alive\r\n" + "Content-Length: 5\r\n\r\n" + "hello"), + // Response to second request. + MockRead("HTTP/1.1 200 OK\r\n" + "Proxy-Connection: keep-alive\r\n" + "Content-Length: 2\r\n\r\n" + "hi"), + }; + + StaticSocketDataProvider data(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + MockWrite data_writes2[] = { + // Initial request using a different NetworkIsolationKey includes the + // cached proxy credentials, but not server credentials. + MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + // Retry with proxy and new server auth credentials, which gets a + // response. + MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" + "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), + }; + + MockRead data_reads2[] = { + // Server auth challenge. + MockRead("HTTP/1.0 401 Authentication Required\r\n" + "Proxy-Connection: keep-alive\r\n" + "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"), + // Response. + MockRead("HTTP/1.1 200 OK\r\n" + "Proxy-Connection: keep-alive\r\n" + "Content-Length: 9\r\n\r\n" + "greetings"), + }; + + StaticSocketDataProvider data2(data_reads2, data_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + + TestCompletionCallback callback; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://myproxy:70/"); + request.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + request.network_isolation_key = kNetworkIsolationKey1; + + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = trans->Start(&request, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_EQ(407, response->headers->response_code()); + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge)); + + rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(401, response->headers->response_code()); + EXPECT_FALSE(response->auth_challenge->is_proxy); + EXPECT_EQ("http://myproxy:70", + response->auth_challenge->challenger.Serialize()); + EXPECT_EQ("MyRealm1", response->auth_challenge->realm); + EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme); + + rv = trans->RestartWithAuth(AuthCredentials(kFoo2, kBar2), + callback.callback()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(200, response->headers->response_code()); + // The password prompt info should not be set. + EXPECT_FALSE(response->auth_challenge.has_value()); + std::string response_data; + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hello", response_data); + + // Check that the proxy credentials were cached correctly. The should be + // accessible with any NetworkIsolationKey. + HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo, entry->credentials().username()); + ASSERT_EQ(kBar, entry->credentials().password()); + EXPECT_EQ(entry, + session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + + // Check that the server credentials were cached correctly. The should be + // accessible with only kNetworkIsolationKey1. + entry = session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo2, entry->credentials().username()); + ASSERT_EQ(kBar2, entry->credentials().password()); + // Looking up the server entry with another NetworkIsolationKey should fail. + EXPECT_FALSE(session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + + // Make another request with a different NetworkIsolationKey. It should use + // another socket, reuse the cached proxy credentials, but result in a server + // auth challenge. + request.network_isolation_key = kNetworkIsolationKey2; + trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + rv = trans->Start(&request, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(401, response->headers->response_code()); + EXPECT_FALSE(response->auth_challenge->is_proxy); + EXPECT_EQ("http://myproxy:70", + response->auth_challenge->challenger.Serialize()); + EXPECT_EQ("MyRealm1", response->auth_challenge->realm); + EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme); + + rv = trans->RestartWithAuth(AuthCredentials(kFoo3, kBar3), + callback.callback()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(200, response->headers->response_code()); + // The password prompt info should not be set. + EXPECT_FALSE(response->auth_challenge.has_value()); + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("greetings", response_data); + + // Check that the proxy credentials are still cached. + entry = session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo, entry->credentials().username()); + ASSERT_EQ(kBar, entry->credentials().password()); + EXPECT_EQ(entry, + session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + + // Check that the correct server credentials are cached for each + // NetworkIsolationKey. + entry = session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo2, entry->credentials().username()); + ASSERT_EQ(kBar2, entry->credentials().password()); + entry = session->http_auth_cache()->Lookup( + GURL("http://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo3, entry->credentials().username()); + ASSERT_EQ(kBar3, entry->credentials().password()); + + // Make a request with the original NetworkIsolationKey. It should reuse the + // first socket, and the proxy credentials sent on the first socket. + request.network_isolation_key = kNetworkIsolationKey1; + trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + rv = trans->Start(&request, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(200, response->headers->response_code()); + // The password prompt info should not be set. + EXPECT_FALSE(response->auth_challenge.has_value()); + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hi", response_data); + + trans.reset(); + session->CloseAllConnections(); +} + +// Much like the test above, but uses tunnelled connections. +TEST_F(HttpNetworkTransactionTest, + BasicAuthProxyMatchesServerAuthWithNetworkIsolationKeyWithTunnel) { + const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1); + const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/")); + const net::NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2); + + // This test would need to use a single socket without this option enabled. + // Best to use this option when it would affect a test, as it will eventually + // become the default behavior. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kPartitionConnectionsByNetworkIsolationKey); + + // Proxy matches request URL. + session_deps_.proxy_resolution_service = + ProxyResolutionService::CreateFixedFromPacResult( + "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS); + BoundTestNetLog log; + session_deps_.net_log = log.bound().net_log(); + session_deps_.key_auth_cache_server_entries_by_network_isolation_key = true; + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + MockWrite data_writes[] = { + // Initial tunnel request gets a proxy auth challenge. + MockWrite("CONNECT myproxy:70 HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + // Retry with proxy auth credentials, which will result in establishing a + // tunnel. + MockWrite("CONNECT myproxy:70 HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + // Request over the tunnel, which gets a server auth challenge. + MockWrite("GET / HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Connection: keep-alive\r\n\r\n"), + // Retry with server auth credentials, which gets a response. + MockWrite("GET / HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Connection: keep-alive\r\n" + "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), + // Another request to the same server and using the same NIK should + // preemptively send the correct cached server + // auth header. Since a tunnel was already established, the proxy headers + // won't be sent again except when establishing another tunnel. + MockWrite("GET / HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Connection: keep-alive\r\n" + "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), + }; + + MockRead data_reads[] = { + // Proxy auth challenge. + MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"), + // Tunnel success + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + // Server auth challenge. + MockRead("HTTP/1.0 401 Authentication Required\r\n" + "Connection: keep-alive\r\n" + "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"), + // Response. + MockRead("HTTP/1.1 200 OK\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 5\r\n\r\n" + "hello"), + // Response to second request. + MockRead("HTTP/1.1 200 OK\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 2\r\n\r\n" + "hi"), + }; + + StaticSocketDataProvider data(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&data); + // One for the proxy connection, one of the server connection. + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + SSLSocketDataProvider ssl2(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); + + MockWrite data_writes2[] = { + // Initial request using a different NetworkIsolationKey includes the + // cached proxy credentials when establishing a tunnel. + MockWrite("CONNECT myproxy:70 HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + // Request over the tunnel, which gets a server auth challenge. Cached + // credentials cannot be used, since the NIK is different. + MockWrite("GET / HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Connection: keep-alive\r\n\r\n"), + // Retry with server auth credentials, which gets a response. + MockWrite("GET / HTTP/1.1\r\n" + "Host: myproxy:70\r\n" + "Connection: keep-alive\r\n" + "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), + }; + + MockRead data_reads2[] = { + // Tunnel success + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + // Server auth challenge. + MockRead("HTTP/1.0 401 Authentication Required\r\n" + "Connection: keep-alive\r\n" + "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"), + // Response. + MockRead("HTTP/1.1 200 OK\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 9\r\n\r\n" + "greetings"), + }; + + StaticSocketDataProvider data2(data_reads2, data_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + // One for the proxy connection, one of the server connection. + SSLSocketDataProvider ssl3(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3); + SSLSocketDataProvider ssl4(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl4); + + TestCompletionCallback callback; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://myproxy:70/"); + request.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + request.network_isolation_key = kNetworkIsolationKey1; + + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = trans->Start(&request, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_EQ(407, response->headers->response_code()); + EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge)); + + rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(401, response->headers->response_code()); + EXPECT_FALSE(response->auth_challenge->is_proxy); + EXPECT_EQ("https://myproxy:70", + response->auth_challenge->challenger.Serialize()); + EXPECT_EQ("MyRealm1", response->auth_challenge->realm); + EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme); + + rv = trans->RestartWithAuth(AuthCredentials(kFoo2, kBar2), + callback.callback()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(200, response->headers->response_code()); + // The password prompt info should not be set. + EXPECT_FALSE(response->auth_challenge.has_value()); + std::string response_data; + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hello", response_data); + + // Check that the proxy credentials were cached correctly. The should be + // accessible with any NetworkIsolationKey. + HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo, entry->credentials().username()); + ASSERT_EQ(kBar, entry->credentials().password()); + EXPECT_EQ(entry, + session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + + // Check that the server credentials were cached correctly. The should be + // accessible with only kNetworkIsolationKey1. + entry = session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo2, entry->credentials().username()); + ASSERT_EQ(kBar2, entry->credentials().password()); + // Looking up the server entry with another NetworkIsolationKey should fail. + EXPECT_FALSE(session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + + // Make another request with a different NetworkIsolationKey. It should use + // another socket, reuse the cached proxy credentials, but result in a server + // auth challenge. + request.network_isolation_key = kNetworkIsolationKey2; + trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + rv = trans->Start(&request, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(401, response->headers->response_code()); + EXPECT_FALSE(response->auth_challenge->is_proxy); + EXPECT_EQ("https://myproxy:70", + response->auth_challenge->challenger.Serialize()); + EXPECT_EQ("MyRealm1", response->auth_challenge->realm); + EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme); + + rv = trans->RestartWithAuth(AuthCredentials(kFoo3, kBar3), + callback.callback()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(200, response->headers->response_code()); + // The password prompt info should not be set. + EXPECT_FALSE(response->auth_challenge.has_value()); + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("greetings", response_data); + + // Check that the proxy credentials are still cached. + entry = session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo, entry->credentials().username()); + ASSERT_EQ(kBar, entry->credentials().password()); + EXPECT_EQ(entry, + session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2)); + + // Check that the correct server credentials are cached for each + // NetworkIsolationKey. + entry = session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo2, entry->credentials().username()); + ASSERT_EQ(kBar2, entry->credentials().password()); + entry = session->http_auth_cache()->Lookup( + GURL("https://myproxy:70"), HttpAuth::AUTH_SERVER, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2); + ASSERT_TRUE(entry); + ASSERT_EQ(kFoo3, entry->credentials().username()); + ASSERT_EQ(kBar3, entry->credentials().password()); + + // Make a request with the original NetworkIsolationKey. It should reuse the + // first socket, and the proxy credentials sent on the first socket. + request.network_isolation_key = kNetworkIsolationKey1; + trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + rv = trans->Start(&request, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_EQ(200, response->headers->response_code()); + // The password prompt info should not be set. + EXPECT_FALSE(response->auth_challenge.has_value()); + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hi", response_data); + + trans.reset(); + session->CloseAllConnections(); +} + // Test that we don't pass extraneous headers from the proxy's response to the // caller when the proxy responds to CONNECT with 407. TEST_F(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) { @@ -18372,8 +18904,8 @@ session->http_auth_cache()->Add( GURL("http://myproxy:70/"), HttpAuth::AUTH_PROXY, "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, "Basic realm=MyRealm1", - AuthCredentials(kFoo, kBar), "/"); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/"); TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
diff --git a/net/http/http_proxy_client_socket_fuzzer.cc b/net/http/http_proxy_client_socket_fuzzer.cc index f253b16f..2b416158 100644 --- a/net/http/http_proxy_client_socket_fuzzer.cc +++ b/net/http/http_proxy_client_socket_fuzzer.cc
@@ -17,6 +17,7 @@ #include "net/base/address_list.h" #include "net/base/auth.h" #include "net/base/host_port_pair.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/http/http_auth_cache.h" #include "net/http/http_auth_handler_basic.h" @@ -47,7 +48,8 @@ // Create auth handler supporting basic and digest schemes. Other schemes can // make system calls, which doesn't seem like a great idea. - net::HttpAuthCache auth_cache; + net::HttpAuthCache auth_cache( + false /* key_server_entries_by_network_isolation_key */); net::HttpAuthHandlerRegistryFactory auth_handler_factory; auth_handler_factory.RegisterSchemeFactory( net::kBasicAuthScheme, new net::HttpAuthHandlerBasic::Factory()); @@ -55,10 +57,10 @@ net::kDigestAuthScheme, new net::HttpAuthHandlerDigest::Factory()); scoped_refptr<net::HttpAuthController> auth_controller( - new net::HttpAuthController( - net::HttpAuth::AUTH_PROXY, GURL("http://proxy:42/"), &auth_cache, - &auth_handler_factory, nullptr, - net::HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); + base::MakeRefCounted<net::HttpAuthController>( + net::HttpAuth::AUTH_PROXY, GURL("http://proxy:42/"), + net::NetworkIsolationKey(), &auth_cache, &auth_handler_factory, + nullptr, net::HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); // Determine if the HttpProxyClientSocket should be told the underlying socket // is HTTPS. net::HttpProxyClientSocket socket(
diff --git a/net/http/http_proxy_connect_job.cc b/net/http/http_proxy_connect_job.cc index 2349095..13efec42 100644 --- a/net/http/http_proxy_connect_job.cc +++ b/net/http/http_proxy_connect_job.cc
@@ -181,10 +181,11 @@ has_established_connection_(false), http_auth_controller_( params_->tunnel() - ? new HttpAuthController( + ? base::MakeRefCounted<HttpAuthController>( HttpAuth::AUTH_PROXY, GURL((params_->ssl_params() ? "https://" : "http://") + GetDestination().ToString()), + params_->network_isolation_key(), common_connect_job_params->http_auth_cache, common_connect_job_params->http_auth_handler_factory, host_resolver(),
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc index e2b39b01..ec441b7 100644 --- a/net/http/http_proxy_connect_job_unittest.cc +++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -755,7 +755,8 @@ : (std::string("https://") + kHttpsProxyHost)); session_->http_auth_cache()->Add( proxy_url, HttpAuth::AUTH_PROXY, "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/"); + NetworkIsolationKey(), "Basic realm=MyRealm1", + AuthCredentials(kFoo, kBar), "/"); for (IoMode io_mode : {SYNCHRONOUS, ASYNC}) { SCOPED_TRACE(io_mode);
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc index e7e6d24..0528ad2d 100644 --- a/net/quic/quic_proxy_client_socket_unittest.cc +++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -175,6 +175,8 @@ user_agent_(kUserAgent), proxy_host_port_(kProxyHost, kProxyPort), endpoint_host_port_(kOriginHost, kOriginPort), + http_auth_cache_( + false /* key_server_entries_by_network_isolation_key */), host_resolver_(new MockCachingHostResolver()), http_auth_handler_factory_(HttpAuthHandlerFactory::CreateDefault()) { IPAddress ip(192, 0, 2, 33); @@ -294,7 +296,8 @@ endpoint_host_port_, net_log_.bound(), new HttpAuthController( HttpAuth::AUTH_PROXY, - GURL("https://" + proxy_host_port_.ToString()), &http_auth_cache_, + GURL("https://" + proxy_host_port_.ToString()), + NetworkIsolationKey(), &http_auth_cache_, http_auth_handler_factory_.get(), host_resolver_.get(), HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS))); @@ -681,8 +684,9 @@ const base::string16 kFoo(base::ASCIIToUTF16("foo")); const base::string16 kBar(base::ASCIIToUTF16("bar")); http_auth_cache_.Add(GURL(kProxyUrl), HttpAuth::AUTH_PROXY, "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, "Basic realm=MyRealm1", - AuthCredentials(kFoo, kBar), "/"); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), + "/"); AssertConnectSucceeds();
diff --git a/net/socket/ssl_connect_job_unittest.cc b/net/socket/ssl_connect_job_unittest.cc index 8355317..3f2b444 100644 --- a/net/socket/ssl_connect_job_unittest.cc +++ b/net/socket/ssl_connect_job_unittest.cc
@@ -131,8 +131,8 @@ const base::string16 kBar(base::ASCIIToUTF16("bar")); session_->http_auth_cache()->Add( GURL("http://proxy:443/"), HttpAuth::AUTH_PROXY, "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, "Basic realm=MyRealm1", - AuthCredentials(kFoo, kBar), "/"); + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/"); } HttpNetworkSession* CreateNetworkSession() {
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index 38551881..3a666c85 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -158,10 +158,10 @@ void AddAuthToCache() { const base::string16 kFoo(base::ASCIIToUTF16("foo")); const base::string16 kBar(base::ASCIIToUTF16("bar")); - session_->http_auth_cache()->Add(GURL(kProxyUrl), HttpAuth::AUTH_PROXY, - "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - AuthCredentials(kFoo, kBar), "/"); + session_->http_auth_cache()->Add( + GURL(kProxyUrl), HttpAuth::AUTH_PROXY, "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(), + "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/"); } void ResumeAndRun() { @@ -269,8 +269,8 @@ spdy_stream, user_agent_, endpoint_host_port_pair_, net_log_.bound(), new HttpAuthController( HttpAuth::AUTH_PROXY, GURL("https://" + proxy_host_port_.ToString()), - session_->http_auth_cache(), session_->http_auth_handler_factory(), - session_->host_resolver(), + NetworkIsolationKey(), session_->http_auth_cache(), + session_->http_auth_handler_factory(), session_->host_resolver(), HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS)); }
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 379530c..791b27c1 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc
@@ -344,8 +344,8 @@ net_log(nullptr), disable_idle_sockets_close_on_memory_pressure(false), enable_early_data(false), - allow_default_credentials( - HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS) { + allow_default_credentials(HttpAuthPreferences::ALLOW_DEFAULT_CREDENTIALS), + key_auth_cache_server_entries_by_network_isolation_key(false) { http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = kDefaultInitialWindowSize; } @@ -400,6 +400,8 @@ session_deps->disable_idle_sockets_close_on_memory_pressure; params.enable_early_data = session_deps->enable_early_data; params.allow_default_credentials = session_deps->allow_default_credentials; + params.key_auth_cache_server_entries_by_network_isolation_key = + session_deps->key_auth_cache_server_entries_by_network_isolation_key; return params; }
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index 304584b3..18c10087 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h
@@ -238,6 +238,7 @@ bool disable_idle_sockets_close_on_memory_pressure; bool enable_early_data; HttpAuthPreferences::DefaultCredentials allow_default_credentials; + bool key_auth_cache_server_entries_by_network_isolation_key; }; class SpdyURLRequestContext : public URLRequestContext {
diff --git a/net/test/embedded_test_server/default_handlers.cc b/net/test/embedded_test_server/default_handlers.cc index 5c63587..b07db80 100644 --- a/net/test/embedded_test_server/default_handlers.cc +++ b/net/test/embedded_test_server/default_handlers.cc
@@ -315,6 +315,25 @@ return http_response; } +// /iframe?URL +// Returns a page that iframes the specified URL. +std::unique_ptr<HttpResponse> HandleIframe(const HttpRequest& request) { + GURL request_url = request.GetURL(); + + auto http_response = std::make_unique<BasicHttpResponse>(); + http_response->set_content_type("text/html"); + + GURL iframe_url("about:blank"); + if (request_url.has_query()) { + iframe_url = GURL(UnescapeBinaryURLComponent(request_url.query())); + } + + http_response->set_content( + base::StringPrintf("<html><body><iframe src=\"%s\"></body></html>", + iframe_url.spec().c_str())); + return http_response; +} + // /nocontent // Returns a NO_CONTENT response. std::unique_ptr<HttpResponse> HandleNoContent(const HttpRequest& request) { @@ -799,6 +818,7 @@ PREFIXED_HANDLER("/expect-and-set-cookie", &HandleExpectAndSetCookie)); server->RegisterDefaultHandler( PREFIXED_HANDLER("/set-header", &HandleSetHeader)); + server->RegisterDefaultHandler(PREFIXED_HANDLER("/iframe", &HandleIframe)); server->RegisterDefaultHandler( PREFIXED_HANDLER("/nocontent", &HandleNoContent)); server->RegisterDefaultHandler(
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 20add8e..cf407a7 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -6965,6 +6965,76 @@ EXPECT_EQ(1, network_delegate.set_cookie_count()); } +// Tests that |key_auth_cache_by_network_isolation_key| is respected. +TEST_F(URLRequestTestHTTP, AuthWithNetworkIsolationKey) { + const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/")); + const NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1); + const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/")); + const NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2); + + ASSERT_TRUE(http_test_server()->Start()); + + for (bool key_auth_cache_by_network_isolation_key : {false, true}) { + TestURLRequestContext url_request_context(true /* delay_initialization */); + std::unique_ptr<HttpNetworkSession::Params> http_network_session_params = + std::make_unique<HttpNetworkSession::Params>(); + http_network_session_params + ->key_auth_cache_server_entries_by_network_isolation_key = + key_auth_cache_by_network_isolation_key; + url_request_context.set_http_network_session_params( + std::move(http_network_session_params)); + url_request_context.Init(); + + // Populate the auth cache using one NetworkIsolationKey. + { + TestDelegate d; + GURL url(base::StringPrintf( + "http://%s:%s@%s/auth-basic", base::UTF16ToASCII(kUser).c_str(), + base::UTF16ToASCII(kSecret).c_str(), + http_test_server()->host_port_pair().ToString().c_str())); + + std::unique_ptr<URLRequest> r(url_request_context.CreateRequest( + url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + r->SetLoadFlags(LOAD_BYPASS_CACHE); + r->set_network_isolation_key(kNetworkIsolationKey1); + r->Start(); + + d.RunUntilComplete(); + EXPECT_THAT(d.request_status(), IsOk()); + ASSERT_TRUE(r->response_headers()); + EXPECT_EQ(200, r->response_headers()->response_code()); + EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos); + } + + // Make a request with another NetworkIsolationKey. This may or may not use + // the cached auth credentials, depending on whether or not the + // HttpAuthCache is configured to respect the NetworkIsolationKey. + { + TestDelegate d; + + std::unique_ptr<URLRequest> r(url_request_context.CreateRequest( + http_test_server()->GetURL("/auth-basic"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + r->SetLoadFlags(LOAD_BYPASS_CACHE); + r->set_network_isolation_key(kNetworkIsolationKey2); + r->Start(); + + d.RunUntilComplete(); + + EXPECT_THAT(d.request_status(), IsOk()); + ASSERT_TRUE(r->response_headers()); + if (key_auth_cache_by_network_isolation_key) { + EXPECT_EQ(401, r->response_headers()->response_code()); + } else { + EXPECT_EQ(200, r->response_headers()->response_code()); + } + + EXPECT_EQ(!key_auth_cache_by_network_isolation_key, + d.data_received().find("user/secret") != std::string::npos); + } + } +} + TEST_F(URLRequestTest, ReportCookieActivity) { HttpTestServer test_server; ASSERT_TRUE(test_server.Start());
diff --git a/services/device/geolocation/geolocation_service_unittest.cc b/services/device/geolocation/geolocation_service_unittest.cc index 9e41e254..8e1a16a1 100644 --- a/services/device/geolocation/geolocation_service_unittest.cc +++ b/services/device/geolocation/geolocation_service_unittest.cc
@@ -112,12 +112,8 @@ #endif // TODO(https://crbug.com/912057): Flaky on Chrome OS / Fails often on *San. -#if defined(OS_CHROMEOS) -#define MAYBE_GeolocationConfig DISABLED_GeolocationConfig -#else -#define MAYBE_GeolocationConfig GeolocationConfig -#endif -TEST_F(GeolocationServiceUnitTest, MAYBE_GeolocationConfig) { +// TODO(https://crbug.com/999409): Also flaky on other platforms. +TEST_F(GeolocationServiceUnitTest, DISABLED_GeolocationConfig) { BindGeolocationConfig(); { base::RunLoop run_loop;
diff --git a/services/network/http_auth_cache_copier.cc b/services/network/http_auth_cache_copier.cc index 7f2697a..5db1cf0 100644 --- a/services/network/http_auth_cache_copier.cc +++ b/services/network/http_auth_cache_copier.cc
@@ -4,6 +4,7 @@ #include "services/network/http_auth_cache_copier.h" +#include "base/logging.h" #include "net/http/http_auth_cache.h" namespace network { @@ -14,7 +15,11 @@ base::UnguessableToken HttpAuthCacheCopier::SaveHttpAuthCache( const net::HttpAuthCache& cache) { base::UnguessableToken key = base::UnguessableToken::Create(); - caches_[key].UpdateAllFrom(cache); + auto cache_it = caches_.emplace(std::make_pair( + key, std::make_unique<net::HttpAuthCache>( + cache.key_server_entries_by_network_isolation_key()))); + DCHECK(cache_it.second); + cache_it.first->second->UpdateAllFrom(cache); return key; } @@ -25,7 +30,12 @@ DLOG(ERROR) << "Unknown HttpAuthCache key: " << key; return; } - cache->UpdateAllFrom(it->second); + + // Source and destination caches must have the same configuration. + DCHECK_EQ(cache->key_server_entries_by_network_isolation_key(), + it->second->key_server_entries_by_network_isolation_key()); + + cache->UpdateAllFrom(*it->second); caches_.erase(it); }
diff --git a/services/network/http_auth_cache_copier.h b/services/network/http_auth_cache_copier.h index 2aa008d5..3af7be75 100644 --- a/services/network/http_auth_cache_copier.h +++ b/services/network/http_auth_cache_copier.h
@@ -6,6 +6,7 @@ #define SERVICES_NETWORK_HTTP_AUTH_CACHE_COPIER_H_ #include <map> +#include <memory> #include "base/macros.h" #include "base/unguessable_token.h" @@ -36,7 +37,7 @@ net::HttpAuthCache* cache); private: - std::map<base::UnguessableToken, net::HttpAuthCache> caches_; + std::map<base::UnguessableToken, std::unique_ptr<net::HttpAuthCache>> caches_; DISALLOW_COPY_AND_ASSIGN(HttpAuthCacheCopier); };
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index aaeab0a2..2d553d92 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -1487,9 +1487,11 @@ std::move(callback).Run(); } -void NetworkContext::AddAuthCacheEntry(const net::AuthChallengeInfo& challenge, - const net::AuthCredentials& credentials, - AddAuthCacheEntryCallback callback) { +void NetworkContext::AddAuthCacheEntry( + const net::AuthChallengeInfo& challenge, + const net::NetworkIsolationKey& network_isolation_key, + const net::AuthCredentials& credentials, + AddAuthCacheEntryCallback callback) { if (challenge.challenger.scheme() == url::kFtpScheme) { #if !BUILDFLAG(DISABLE_FTP_SUPPORT) net::FtpAuthCache* auth_cache = url_request_context_->ftp_auth_cache(); @@ -1507,7 +1509,8 @@ : net::HttpAuth::AUTH_SERVER, challenge.realm, net::HttpAuth::StringToScheme(challenge.scheme), - challenge.challenge, credentials, challenge.path); + network_isolation_key, challenge.challenge, + credentials, challenge.path); } std::move(callback).Run(); } @@ -1519,8 +1522,12 @@ url_request_context_->http_transaction_factory() ->GetSession() ->http_auth_cache(); - net::HttpAuthCache::Entry* entry = http_auth_cache->LookupByPath( - url.GetOrigin(), net::HttpAuth::AUTH_SERVER, url.path()); + // TODO(mmenke): Make NetworkIsolationKey an argument to this method. The one + // consumer of it is associated with a ResourceRequest, so can have the + // consumer grab it from there. + net::HttpAuthCache::Entry* entry = + http_auth_cache->LookupByPath(url.GetOrigin(), net::HttpAuth::AUTH_SERVER, + net::NetworkIsolationKey(), url.path()); if (entry && entry->scheme() == net::HttpAuth::AUTH_SCHEME_BASIC) std::move(callback).Run(entry->credentials()); else @@ -1820,6 +1827,11 @@ session_params.disable_idle_sockets_close_on_memory_pressure = params_->disable_idle_sockets_close_on_memory_pressure; + if (network_service_) { + session_params.key_auth_cache_server_entries_by_network_isolation_key = + network_service_->split_auth_cache_by_network_isolation_key(); + } + builder.set_http_network_session_params(session_params); builder.SetCreateHttpTransactionFactoryCallback(
diff --git a/services/network/network_context.h b/services/network/network_context.h index 17be40c..4378529b 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h
@@ -68,6 +68,7 @@ class CertVerifier; class CertVerifyProc; class HostPortPair; +class NetworkIsolationKey; class ReportSender; class StaticHttpUserAgentSettings; class URLRequestContext; @@ -358,6 +359,7 @@ void LoadHttpAuthCache(const base::UnguessableToken& cache_key, LoadHttpAuthCacheCallback callback) override; void AddAuthCacheEntry(const net::AuthChallengeInfo& challenge, + const net::NetworkIsolationKey& network_isolation_key, const net::AuthCredentials& credentials, AddAuthCacheEntryCallback callback) override; // TODO(mmenke): Rename this method and update Mojo docs to make it clear this
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 9661505..7a48882c 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -1570,19 +1570,21 @@ base::string16 user = base::ASCIIToUTF16("user"); base::string16 password = base::ASCIIToUTF16("pass"); cache->Add(origin, net::HttpAuth::AUTH_SERVER, "Realm1", - net::HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm1", - net::AuthCredentials(user, password), "/"); + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + "basic realm=Realm1", net::AuthCredentials(user, password), "/"); test_clock.Advance(base::TimeDelta::FromHours(1)); // Time now 13:00 cache->Add(origin, net::HttpAuth::AUTH_PROXY, "Realm2", - net::HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm2", - net::AuthCredentials(user, password), "/"); + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + "basic realm=Realm2", net::AuthCredentials(user, password), "/"); ASSERT_EQ(2u, cache->GetEntriesSizeForTesting()); ASSERT_NE(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_SERVER, "Realm1", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); ASSERT_NE(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_PROXY, "Realm2", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); base::RunLoop run_loop; base::Time test_time; @@ -1592,9 +1594,11 @@ EXPECT_EQ(1u, cache->GetEntriesSizeForTesting()); EXPECT_NE(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_SERVER, "Realm1", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); EXPECT_EQ(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_PROXY, "Realm2", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); } TEST_F(NetworkContextTest, ClearAllHttpAuthCache) { @@ -1615,19 +1619,21 @@ base::string16 user = base::ASCIIToUTF16("user"); base::string16 password = base::ASCIIToUTF16("pass"); cache->Add(origin, net::HttpAuth::AUTH_SERVER, "Realm1", - net::HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm1", - net::AuthCredentials(user, password), "/"); + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + "basic realm=Realm1", net::AuthCredentials(user, password), "/"); test_clock.Advance(base::TimeDelta::FromHours(1)); // Time now 13:00 cache->Add(origin, net::HttpAuth::AUTH_PROXY, "Realm2", - net::HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm2", - net::AuthCredentials(user, password), "/"); + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + "basic realm=Realm2", net::AuthCredentials(user, password), "/"); ASSERT_EQ(2u, cache->GetEntriesSizeForTesting()); ASSERT_NE(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_SERVER, "Realm1", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); ASSERT_NE(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_PROXY, "Realm2", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); base::RunLoop run_loop; network_context->ClearHttpAuthCache(base::Time(), run_loop.QuitClosure()); @@ -1635,9 +1641,11 @@ EXPECT_EQ(0u, cache->GetEntriesSizeForTesting()); EXPECT_EQ(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_SERVER, "Realm1", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); EXPECT_EQ(nullptr, cache->Lookup(origin, net::HttpAuth::AUTH_PROXY, "Realm2", - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); } TEST_F(NetworkContextTest, ClearEmptyHttpAuthCache) { @@ -1672,11 +1680,11 @@ base::string16 user = base::ASCIIToUTF16("user"); base::string16 password = base::ASCIIToUTF16("pass"); cache->Add(origin, net::HttpAuth::AUTH_SERVER, "Realm", - net::HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm", - net::AuthCredentials(user, password), "/"); + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + "basic realm=Realm", net::AuthCredentials(user, password), "/"); cache->Add(origin2, net::HttpAuth::AUTH_PROXY, "Realm", - net::HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm", - net::AuthCredentials(user, password), "/"); + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(), + "basic realm=Realm", net::AuthCredentials(user, password), "/"); base::RunLoop run_loop1; base::Optional<net::AuthCredentials> result; @@ -5726,7 +5734,7 @@ network_context->url_request_context()->ftp_auth_cache()->Lookup(url)); base::RunLoop run_loop; network_context->AddAuthCacheEntry( - challenge, + challenge, net::NetworkIsolationKey(), net::AuthCredentials(base::ASCIIToUTF16(kUsername), base::ASCIIToUTF16(kPassword)), run_loop.QuitClosure()); @@ -5815,6 +5823,9 @@ ->GetSession() ->http_auth_cache(); ASSERT_TRUE(cache); + // |key_server_entries_by_network_isolation_key| should be disabled by + // default, so the passed in NetworkIsolationKeys don't matter. + EXPECT_FALSE(cache->key_server_entries_by_network_isolation_key()); // Add an AUTH_SERVER cache entry. GURL url("http://example.test/"); @@ -5826,17 +5837,18 @@ const char kUsername[] = "test_user"; const char kPassword[] = "test_pass"; ASSERT_FALSE(cache->Lookup(url, net::HttpAuth::AUTH_SERVER, challenge.realm, - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); base::RunLoop run_loop; network_context->AddAuthCacheEntry( - challenge, + challenge, net::NetworkIsolationKey(), net::AuthCredentials(base::ASCIIToUTF16(kUsername), base::ASCIIToUTF16(kPassword)), run_loop.QuitClosure()); run_loop.Run(); - net::HttpAuthCache::Entry* entry = - cache->Lookup(url, net::HttpAuth::AUTH_SERVER, challenge.realm, - net::HttpAuth::AUTH_SCHEME_BASIC); + net::HttpAuthCache::Entry* entry = cache->Lookup( + url, net::HttpAuth::AUTH_SERVER, challenge.realm, + net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(url, entry->origin()); EXPECT_EQ(challenge.realm, entry->realm()); @@ -5845,7 +5857,8 @@ EXPECT_EQ(base::ASCIIToUTF16(kPassword), entry->credentials().password()); // Entry should only have been added for server auth. EXPECT_FALSE(cache->Lookup(url, net::HttpAuth::AUTH_PROXY, challenge.realm, - net::HttpAuth::AUTH_SCHEME_BASIC)); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); // Add an AUTH_PROXY cache entry. GURL proxy_url("http://proxy.test/"); @@ -5854,17 +5867,18 @@ const char kProxyUsername[] = "test_proxy_user"; const char kProxyPassword[] = "test_proxy_pass"; ASSERT_FALSE(cache->Lookup(proxy_url, net::HttpAuth::AUTH_PROXY, - challenge.realm, - net::HttpAuth::AUTH_SCHEME_BASIC)); + challenge.realm, net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); base::RunLoop run_loop2; network_context->AddAuthCacheEntry( - challenge, + challenge, net::NetworkIsolationKey(), net::AuthCredentials(base::ASCIIToUTF16(kProxyUsername), base::ASCIIToUTF16(kProxyPassword)), run_loop2.QuitClosure()); run_loop2.Run(); entry = cache->Lookup(proxy_url, net::HttpAuth::AUTH_PROXY, challenge.realm, - net::HttpAuth::AUTH_SCHEME_BASIC); + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey()); ASSERT_TRUE(entry); EXPECT_EQ(proxy_url, entry->origin()); EXPECT_EQ(challenge.realm, entry->realm()); @@ -5875,8 +5889,58 @@ entry->credentials().password()); // Entry should only have been added for proxy auth. EXPECT_FALSE(cache->Lookup(proxy_url, net::HttpAuth::AUTH_SERVER, - challenge.realm, - net::HttpAuth::AUTH_SCHEME_BASIC)); + challenge.realm, net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); +} + +TEST_F(NetworkContextTest, AddHttpAuthCacheEntryWithNetworkIsolationKey) { + network_service()->SetSplitAuthCacheByNetworkIsolationKey(true); + + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(CreateContextParams()); + + net::HttpAuthCache* cache = network_context->url_request_context() + ->http_transaction_factory() + ->GetSession() + ->http_auth_cache(); + ASSERT_TRUE(cache); + // If this isn't true, the rest of this test is pretty meaningless. + ASSERT_TRUE(cache->key_server_entries_by_network_isolation_key()); + + // Add an AUTH_SERVER cache entry. + GURL url("http://example.test/"); + url::Origin origin = url::Origin::Create(url); + net::NetworkIsolationKey network_isolation_key(origin, origin); + net::AuthChallengeInfo challenge; + challenge.is_proxy = false; + challenge.challenger = origin; + challenge.scheme = "basic"; + challenge.realm = "testrealm"; + const char kUsername[] = "test_user"; + const char kPassword[] = "test_pass"; + ASSERT_FALSE(cache->Lookup(url, net::HttpAuth::AUTH_SERVER, challenge.realm, + net::HttpAuth::AUTH_SCHEME_BASIC, + network_isolation_key)); + base::RunLoop run_loop; + network_context->AddAuthCacheEntry( + challenge, network_isolation_key, + net::AuthCredentials(base::ASCIIToUTF16(kUsername), + base::ASCIIToUTF16(kPassword)), + run_loop.QuitClosure()); + run_loop.Run(); + net::HttpAuthCache::Entry* entry = + cache->Lookup(url, net::HttpAuth::AUTH_SERVER, challenge.realm, + net::HttpAuth::AUTH_SCHEME_BASIC, network_isolation_key); + ASSERT_TRUE(entry); + EXPECT_EQ(url, entry->origin()); + EXPECT_EQ(challenge.realm, entry->realm()); + EXPECT_EQ(net::HttpAuth::StringToScheme(challenge.scheme), entry->scheme()); + EXPECT_EQ(base::ASCIIToUTF16(kUsername), entry->credentials().username()); + EXPECT_EQ(base::ASCIIToUTF16(kPassword), entry->credentials().password()); + // Entry should only be accessibly when using the correct NetworkIsolationKey. + EXPECT_FALSE(cache->Lookup(url, net::HttpAuth::AUTH_SERVER, challenge.realm, + net::HttpAuth::AUTH_SCHEME_BASIC, + net::NetworkIsolationKey())); } TEST_F(NetworkContextTest, HSTSPolicyBypassList) {
diff --git a/services/network/network_service.cc b/services/network/network_service.cc index 3954b14..10d1e215 100644 --- a/services/network/network_service.cc +++ b/services/network/network_service.cc
@@ -656,6 +656,13 @@ env->SetVar(variable->name, variable->value); } +void NetworkService::SetSplitAuthCacheByNetworkIsolationKey( + bool split_auth_cache_by_network_isolation_key) { + DCHECK(network_contexts_.empty()); + split_auth_cache_by_network_isolation_key_ = + split_auth_cache_by_network_isolation_key; +} + #if defined(OS_ANDROID) void NetworkService::DumpWithoutCrashing(base::Time dump_request_time) { static base::debug::CrashKeyString* time_key =
diff --git a/services/network/network_service.h b/services/network/network_service.h index 1218342..ac17779e 100644 --- a/services/network/network_service.h +++ b/services/network/network_service.h
@@ -166,6 +166,8 @@ #endif void SetEnvironment( std::vector<mojom::EnvironmentVariablePtr> environment) override; + void SetSplitAuthCacheByNetworkIsolationKey( + bool split_auth_cache_by_network_isolation_key) override; #if defined(OS_ANDROID) void DumpWithoutCrashing(base::Time dump_request_time) override; #endif @@ -216,6 +218,10 @@ host_resolver_factory_ = std::move(host_resolver_factory); } + bool split_auth_cache_by_network_isolation_key() const { + return split_auth_cache_by_network_isolation_key_; + } + static NetworkService* GetNetworkServiceForTesting(); private: @@ -314,6 +320,10 @@ // A timer that periodically calls ReportMetrics every hour. base::RepeatingTimer metrics_trigger_timer_; + // Whether new NetworkContexts will be configured to partition their + // HttpAuthCaches by NetworkIsolationKey. + bool split_auth_cache_by_network_isolation_key_ = false; + DISALLOW_COPY_AND_ASSIGN(NetworkService); };
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc index 71ff6555..5a92e9b 100644 --- a/services/network/network_service_unittest.cc +++ b/services/network/network_service_unittest.cc
@@ -38,6 +38,8 @@ #include "net/dns/public/dns_protocol.h" #include "net/http/http_auth_handler_factory.h" #include "net/http/http_auth_scheme.h" +#include "net/http/http_network_session.h" +#include "net/http/http_transaction_factory.h" #include "net/net_buildflags.h" #include "net/proxy_resolution/proxy_config.h" #include "net/socket/client_socket_pool_manager.h" @@ -1636,6 +1638,32 @@ } } +TEST_F(NetworkServiceTest, SplitAuthCacheByNetworkIsolationKey) { + service()->SetSplitAuthCacheByNetworkIsolationKey(true); + mojo::Remote<mojom::NetworkContext> network_context_remote; + NetworkContext network_context( + service(), network_context_remote.BindNewPipeAndPassReceiver(), + CreateContextParams()); + EXPECT_TRUE(network_context.url_request_context() + ->http_transaction_factory() + ->GetSession() + ->params() + .key_auth_cache_server_entries_by_network_isolation_key); +} + +TEST_F(NetworkServiceTest, NoSplitAuthCacheByNetworkIsolationKey) { + service()->SetSplitAuthCacheByNetworkIsolationKey(false); + mojo::Remote<mojom::NetworkContext> network_context_remote; + NetworkContext network_context( + service(), network_context_remote.BindNewPipeAndPassReceiver(), + CreateContextParams()); + EXPECT_FALSE(network_context.url_request_context() + ->http_transaction_factory() + ->GetSession() + ->params() + .key_auth_cache_server_entries_by_network_isolation_key); +} + } // namespace } // namespace network
diff --git a/services/network/proxy_resolving_client_socket_unittest.cc b/services/network/proxy_resolving_client_socket_unittest.cc index 5570943..fc1fe29 100644 --- a/services/network/proxy_resolving_client_socket_unittest.cc +++ b/services/network/proxy_resolving_client_socket_unittest.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/dns/mock_host_resolver.h" #include "net/proxy_resolution/mock_proxy_resolver.h" @@ -467,14 +468,14 @@ auth_cache->Add(GURL("http://bad:99"), net::HttpAuth::AUTH_PROXY, "test_realm", net::HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=\"test_realm\"", + net::NetworkIsolationKey(), "Basic realm=\"test_realm\"", net::AuthCredentials(base::ASCIIToUTF16("user"), base::ASCIIToUTF16("password")), std::string()); auth_cache->Add(GURL("http://bad:99"), net::HttpAuth::AUTH_PROXY, "test_realm2", net::HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=\"test_realm2\"", + net::NetworkIsolationKey(), "Basic realm=\"test_realm2\"", net::AuthCredentials(base::ASCIIToUTF16("user2"), base::ASCIIToUTF16("password2")), std::string()); @@ -531,7 +532,7 @@ // origin + realm + scheme lookup. auth_cache->Add(GURL("http://bad:99"), net::HttpAuth::AUTH_PROXY, "test_realm", net::HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=\"test_realm\"", + net::NetworkIsolationKey(), "Basic realm=\"test_realm\"", net::AuthCredentials(base::ASCIIToUTF16("user"), base::ASCIIToUTF16("password")), std::string()); @@ -565,7 +566,7 @@ // origin + realm + scheme lookup. auth_cache->Add(GURL("http://bad:99"), net::HttpAuth::AUTH_PROXY, "test_realm", net::HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=\"test_realm\"", + net::NetworkIsolationKey(), "Basic realm=\"test_realm\"", net::AuthCredentials(base::ASCIIToUTF16("user"), base::ASCIIToUTF16("password")), std::string()); @@ -629,7 +630,7 @@ auth_cache->Add(GURL("http://bad:99"), net::HttpAuth::AUTH_PROXY, "test_realm", net::HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=\"test_realm\"", + net::NetworkIsolationKey(), "Basic realm=\"test_realm\"", net::AuthCredentials(base::ASCIIToUTF16("user"), base::ASCIIToUTF16("password")), "/");
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index b60048c..e014b8c 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -1181,10 +1181,15 @@ LoadHttpAuthCache(mojo_base.mojom.UnguessableToken cache_key) => (); // Adds an entry to the HttpAuthCache or FtpAuthCache (determined by whether - // the |challenger| field within |challenge| is an ftp:// URL). |challenge| - // may not necessarily contain a stateful challenge that requires a persistent - // connection, allowing the cache to be pre-populated. + // the |challenger| field within |challenge| is an ftp:// URL). + // |network_isolation_key| is the NetworkIsolationKey to restrict the + // credentials to, and is only respected for server (not proxy) HTTP auth + // and only when the NetworkService was configured to split the auth cache by + // NetworkIsolationKey. |challenge| may not necessarily contain a stateful + // challenge that requires a persistent connection, allowing the cache to be + // pre-populated. AddAuthCacheEntry(AuthChallengeInfo challenge, + NetworkIsolationKey network_isolation_key, AuthCredentials credentials) => (); // Looks up credentials in the HttpAuthCache using the origin and path from
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom index c1ae348..4a1dc2e 100644 --- a/services/network/public/mojom/network_service.mojom +++ b/services/network/public/mojom/network_service.mojom
@@ -338,6 +338,12 @@ // |environment| array. SetEnvironment(array<EnvironmentVariable> environment); + // Sets whether the HTTP auth cache will be split the NetworkIsolationKey. + // Only affects server (not proxy) credentials. May only be called before any + // NetworkContexts have been created. Defaults to false. + SetSplitAuthCacheByNetworkIsolationKey( + bool split_auth_cache_by_network_isolation_key); + // Calls base::debug::DumpWithoutCrashing for the network process. // TODO(http://crbug.com/934317): Remove this once done debugging renderer // hangs.
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h index 0c05d9a8..046b2df 100644 --- a/services/network/test/test_network_context.h +++ b/services/network/test/test_network_context.h
@@ -235,6 +235,7 @@ void LoadHttpAuthCache(const base::UnguessableToken& cache_key, LoadHttpAuthCacheCallback callback) override {} void AddAuthCacheEntry(const net::AuthChallengeInfo& challenge, + const net::NetworkIsolationKey& network_isolation_key, const net::AuthCredentials& credentials, AddAuthCacheEntryCallback callback) override {} void LookupBasicAuthCredentials(
diff --git a/services/network/udp_socket_unittest.cc b/services/network/udp_socket_unittest.cc index f6cc0b9..d7a9f51 100644 --- a/services/network/udp_socket_unittest.cc +++ b/services/network/udp_socket_unittest.cc
@@ -279,9 +279,18 @@ EXPECT_EQ(net::ERR_UNEXPECTED, result); } +// TODO(crbug.com/1014916): These two tests are very flaky on Fuchsia. +#if defined(OS_FUCHSIA) +#define MAYBE_TestReadSendTo DISABLED_TestReadSendTo +#define MAYBE_TestUnexpectedSequences DISABLED_TestUnexpectedSequences +#else +#define MAYBE_TestReadSendTo TestReadSendTo +#define MAYBE_TestUnexpectedSequences TestUnexpectedSequences +#endif + // Tests that the sequence of calling Bind()/Connect() and setters is // important. -TEST_F(UDPSocketTest, TestUnexpectedSequences) { +TEST_F(UDPSocketTest, MAYBE_TestUnexpectedSequences) { mojo::Remote<mojom::UDPSocket> socket_remote; factory()->CreateUDPSocket(socket_remote.BindNewPipeAndPassReceiver(), mojo::NullRemote()); @@ -487,7 +496,7 @@ EXPECT_EQ(msg, result.data.value()); } -TEST_F(UDPSocketTest, TestReadSendTo) { +TEST_F(UDPSocketTest, MAYBE_TestReadSendTo) { // Create a server socket to send data. mojo::Remote<mojom::UDPSocket> server_socket; factory()->CreateUDPSocket(server_socket.BindNewPipeAndPassReceiver(),
diff --git a/services/tracing/perfetto/json_exporter_main.cc b/services/tracing/perfetto/json_exporter_main.cc index 90868ec..e3c65402 100644 --- a/services/tracing/perfetto/json_exporter_main.cc +++ b/services/tracing/perfetto/json_exporter_main.cc
@@ -42,7 +42,8 @@ std::vector<perfetto::TracePacket> packets; for (auto it = decoder.packet(); !!it; ++it) { perfetto::TracePacket trace_packet; - trace_packet.AddSlice(it->data(), it->size()); + auto const_bytes = *it; + trace_packet.AddSlice(const_bytes.data, const_bytes.size); packets.emplace_back(std::move(trace_packet)); } exporter.OnTraceData(std::move(packets), false);
diff --git a/services/tracing/perfetto/privacy_filtering_check.cc b/services/tracing/perfetto/privacy_filtering_check.cc index 4ca40f4..6dacb68 100644 --- a/services/tracing/perfetto/privacy_filtering_check.cc +++ b/services/tracing/perfetto/privacy_filtering_check.cc
@@ -76,7 +76,7 @@ serialized_trace_proto.size()); for (auto it = trace.packet(); !!it; ++it) { - TracePacket::Decoder packet(it->data(), it->size()); + TracePacket::Decoder packet(*it); const MessageInfo* root = &kTracePacket; VerifyProto(root, &packet);
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index a63bf2b6..97efe6d 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -512,9 +512,10 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "gpu": "102b:0532", + "gpu": "102b:0532-6.1.7600.16385", "os": "Windows-2008ServerR2-SP1", - "pool": "chrome.tests.perf" + "pool": "chrome.tests.perf", + "synthetic_product_name": "PowerEdge R210 II (Dell Inc.)" } ], "expiration": 7200, @@ -549,9 +550,10 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "gpu": "102b:0532", + "gpu": "102b:0532-6.1.7600.16385", "os": "Windows-2008ServerR2-SP1", - "pool": "chrome.tests.perf" + "pool": "chrome.tests.perf", + "synthetic_product_name": "PowerEdge R210 II (Dell Inc.)" } ], "expiration": 7200, @@ -586,9 +588,10 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "gpu": "102b:0532", + "gpu": "102b:0532-6.1.7600.16385", "os": "Windows-2008ServerR2-SP1", - "pool": "chrome.tests.perf" + "pool": "chrome.tests.perf", + "synthetic_product_name": "PowerEdge R210 II (Dell Inc.)" } ], "expiration": 7200, @@ -626,9 +629,10 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "gpu": "102b:0532", + "gpu": "102b:0532-6.1.7600.16385", "os": "Windows-2008ServerR2-SP1", - "pool": "chrome.tests.perf" + "pool": "chrome.tests.perf", + "synthetic_product_name": "PowerEdge R210 II (Dell Inc.)" } ], "expiration": 7200,
diff --git a/testing/buildbot/filters/bfcache.chrome_public_test_apk.filter b/testing/buildbot/filters/bfcache.chrome_public_test_apk.filter index d6ef6877..ab97355 100644 --- a/testing/buildbot/filters/bfcache.chrome_public_test_apk.filter +++ b/testing/buildbot/filters/bfcache.chrome_public_test_apk.filter
@@ -7,11 +7,20 @@ -org.chromium.chrome.browser.FeaturesAnnotationsTest.testFeaturesSetExistingFlags -org.chromium.chrome.browser.FeaturesAnnotationsTest.testFeaturesDoNotRemoveExistingFlags -# Not triaged yet. See https://crbug.com/1006267 -# Reproduce with --enable-features=BackForwardCache,BackForwardCacheNoTimeEviction --org.chromium.chrome.browser.offlinepages.OfflinePageAutoFetchTest --org.chromium.chrome.browser.offlinepages.indicator.OfflineIndicatorControllerTest - -# Not triaged yet. See https://crbug.com/1006267 -# This fails even without bfcache flags but keep it disabled just for now. +# Failing on bfcache-android-debug and 4.4.4 locally. See https://crbug.com/1006267 +-org.chromium.chrome.browser.SafeBrowsingTest.interstitialPage +-org.chromium.chrome.browser.WarmupManagerTest.testCreateAndTakeSpareRenderer +-org.chromium.chrome.browser.customtabs.DetachedResourceRequestTest.testSafeBrowsingSubresource +# This one is flaky +-org.chromium.chrome.browser.customtabs.DetachedResourceRequestTest.testSafeBrowsingSubresourceBeforeNative -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testRedirectionFromIntent +-org.chromium.chrome.browser.incognito.IncognitoTabLauncherTest.testLaunchIncognitoNewTab +-org.chromium.chrome.browser.incognito.IncognitoTabLauncherTest.testLaunchIncognitoNewTab_omniboxFocused +-org.chromium.chrome.browser.infobar.InfoBarTest.testInfoBarForGeolocationDisappearsOnBack +-org.chromium.chrome.browser.profiling_host.ProfilingProcessHostAndroidTest.testModeBrowser +-org.chromium.chrome.browser.tabmodel.IncognitoTabModelTest.testRecreateInIncognito +-org.chromium.chrome.browser.toolbar.top.BrandColorTest.testBrandColorInterstitial +# These 3 are flaky +-org.chromium.chrome.browser.offlinepages.OfflinePageAutoFetchTest +-org.chromium.chrome.browser.notifications.NotificationPlatformBridgeIntentTest.testLaunchNotificationPreferencesForCategory +-org.chromium.chrome.browser.notifications.NotificationPlatformBridgeIntentTest.testLaunchNotificationPreferencesForWebsite
diff --git a/testing/libfuzzer/fuzzers/dicts/date.dict b/testing/libfuzzer/fuzzers/dicts/date.dict new file mode 100644 index 0000000..a684685 --- /dev/null +++ b/testing/libfuzzer/fuzzers/dicts/date.dict
@@ -0,0 +1,40 @@ +# Copyright 2019 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. + +# Fields +"G" +"y" +"u" +"Q" +"q" +"M" +"L" +"w" +"W" +"d" +"D" +"F" +"g" +"E" +"e" +"c" +"a" +"h" +"H" +"K" +"k" +"m" +"s" +"S" +"A" +"z" +"Z" +"v" +# Quote +"'" +# Separators +"." +":" +"," +"\""
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py index f9310e48..e334565 100755 --- a/testing/scripts/run_performance_tests.py +++ b/testing/scripts/run_performance_tests.py
@@ -348,8 +348,9 @@ return_code = xvfb.run_executable( command, env=env, stdoutfile=output_paths.logs) else: - return_code = test_env.run_command_with_output( - command, env=env, stdoutfile=output_paths.logs) + with open(output_paths.logs, 'w') as handle: + return_code = test_env.run_command_output_to_handle( + command, handle, env=env) expected_results_filename = os.path.join(temp_dir, 'test-results.json') if os.path.exists(expected_results_filename): shutil.move(expected_results_filename, output_paths.test_results)
diff --git a/testing/scripts/run_wpt_tests.py b/testing/scripts/run_wpt_tests.py index 4fdf2fc9..30bf0a23 100755 --- a/testing/scripts/run_wpt_tests.py +++ b/testing/scripts/run_wpt_tests.py
@@ -20,6 +20,10 @@ import common +BLINK_TOOLS_DIR = os.path.join(common.SRC_DIR, 'third_party', 'blink', 'tools') +WPT_METADATA_DIR = "../../wpt_expectations_metadata/" +WPT_OVERRIDE_EXPECTATIONS_PATH = ( + "../../third_party/blink/web_tests/WPTOverrideExpectations") class WPTTestAdapter(common.BaseIsolatedScriptArgsAdapter): @@ -55,7 +59,8 @@ "--no-manifest-download", "--no-pause-after-test", "--no-fail-on-unexpected", - "--metadata=../../out/Release/wpt_expectations_metadata/", + "--metadata", + WPT_METADATA_DIR, # By specifying metadata above, WPT will try to find manifest in the # metadata directory. So here we point it back to the correct path # for the manifest. @@ -80,18 +85,28 @@ def clean_up_after_test_run(self): common.run_command([ sys.executable, - os.path.join(common.SRC_DIR, 'third_party', 'blink', 'tools', - 'update_wpt_output.py'), + os.path.join(BLINK_TOOLS_DIR, 'update_wpt_output.py'), + '--verbose', '--old-json-output-file-path', self.options.old_json_output_file_path, '--new-json-output-dir', self.options.new_json_output_dir, '--new-json-output-filename', self.options.new_json_output_filename, '--additional-expectations', - '../../third_party/blink/web_tests/WPTOverrideExpectations', + WPT_OVERRIDE_EXPECTATIONS_PATH ]) def main(): + # First, generate WPT metadata files. + common.run_command([ + sys.executable, + os.path.join(BLINK_TOOLS_DIR, 'build_wpt_metadata.py'), + "--metadata-output-dir", + WPT_METADATA_DIR, + "--additional-expectations", + WPT_OVERRIDE_EXPECTATIONS_PATH + ]) + adapter = WPTTestAdapter() return adapter.run_test()
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index c811611..894f5b3 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2860,30 +2860,6 @@ ] } ], - "GwpAsanUnified": [ - { - "platforms": [ - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "params": { - "AllocationSamplingRange": "16", - "MaxAllocations": "70", - "MaxMetadata": "255", - "ProcessSamplingBoost2": "10", - "ProcessSamplingProbability": "0.015" - }, - "enable_features": [ - "GwpAsanMalloc", - "GwpAsanPartitionAlloc" - ] - } - ] - } - ], "HTTPReallyBadFinal": [ { "platforms": [ @@ -5377,6 +5353,27 @@ ] } ], + "SavePasswordIllustration": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "params": { + "image": "1" + }, + "enable_features": [ + "SavePasswordIllustration" + ] + } + ] + } + ], "SchedulerConfiguration": [ { "platforms": [
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index 8ced46ef..a011b6a 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -162,13 +162,11 @@ "platform/modules/mediastream/web_platform_media_stream_source.h", "platform/modules/mediastream/web_platform_media_stream_track.h", "platform/modules/mediastream/webrtc_uma_histograms.h", - "platform/modules/peerconnection/audio_codec_factory.h", "platform/modules/peerconnection/rtc_event_log_output_sink.h", "platform/modules/peerconnection/rtc_event_log_output_sink_proxy_util.h", "platform/modules/peerconnection/two_keys_adapter_map.h", "platform/modules/peerconnection/webrtc_audio_sink.h", "platform/modules/peerconnection/webrtc_util.h", - "platform/modules/peerconnection/webrtc_video_track_source.h", "platform/modules/remoteplayback/web_remote_playback_client.h", "platform/modules/service_worker/web_service_worker_error.h", "platform/modules/service_worker/web_service_worker_network_provider.h", @@ -383,7 +381,6 @@ "web/modules/mediastream/web_media_stream_renderer_factory.h", "web/modules/mediastream/web_media_stream_utils.h", "web/modules/mediastream/webmediaplayer_ms.h", - "web/modules/peerconnection/media_stream_remote_video_source.h", "web/modules/peerconnection/media_stream_video_webrtc_sink.h", "web/modules/peerconnection/peer_connection_dependency_factory.h", "web/modules/peerconnection/rtc_rtp_receiver_impl.h",
diff --git a/third_party/blink/public/platform/modules/peerconnection/audio_codec_factory.h b/third_party/blink/public/platform/modules/peerconnection/audio_codec_factory.h deleted file mode 100644 index ad000a8c..0000000 --- a/third_party/blink/public/platform/modules/peerconnection/audio_codec_factory.h +++ /dev/null
@@ -1,23 +0,0 @@ -// 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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_AUDIO_CODEC_FACTORY_H_ -#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_AUDIO_CODEC_FACTORY_H_ - -#include "third_party/blink/public/platform/web_common.h" -#include "third_party/webrtc/api/audio_codecs/audio_decoder_factory.h" -#include "third_party/webrtc/api/audio_codecs/audio_encoder_factory.h" -#include "third_party/webrtc/api/scoped_refptr.h" - -namespace blink { - -BLINK_PLATFORM_EXPORT rtc::scoped_refptr<webrtc::AudioEncoderFactory> -CreateWebrtcAudioEncoderFactory(); - -BLINK_PLATFORM_EXPORT rtc::scoped_refptr<webrtc::AudioDecoderFactory> -CreateWebrtcAudioDecoderFactory(); - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_AUDIO_CODEC_FACTORY_H_
diff --git a/third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h b/third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h index 8451b86..ec6c7379 100644 --- a/third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h +++ b/third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h
@@ -190,6 +190,7 @@ const base::Optional<int>& requested_buffer_size, bool disable_local_echo, bool enable_automatic_output_device_selection, + ProcessingType processing_type, const AudioProcessingProperties& audio_processing_properties); AudioCaptureSettings(const AudioCaptureSettings& other); AudioCaptureSettings& operator=(const AudioCaptureSettings& other); @@ -216,6 +217,10 @@ DCHECK(HasValue()); return render_to_associated_sink_; } + ProcessingType processing_type() const { + DCHECK(HasValue()); + return processing_type_; + } AudioProcessingProperties audio_processing_properties() const { DCHECK(HasValue()); return audio_processing_properties_; @@ -227,6 +232,7 @@ base::Optional<int> requested_buffer_size_; bool disable_local_echo_; bool render_to_associated_sink_; + ProcessingType processing_type_; AudioProcessingProperties audio_processing_properties_; };
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_document.h b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_document.h index f5e599f..f28dccb 100644 --- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_document.h +++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_document.h
@@ -14,7 +14,6 @@ #include "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" -#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_document.h" #include "third_party/blink/renderer/bindings/tests/idls/core/test_interface_document.h"
diff --git a/third_party/blink/renderer/core/css/css_value.h b/third_party/blink/renderer/core/css/css_value.h index 8b24591..94a011c 100644 --- a/third_party/blink/renderer/core/css/css_value.h +++ b/third_party/blink/renderer/core/css/css_value.h
@@ -33,13 +33,14 @@ class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> { public: + template <typename T> static void* AllocateObject(size_t size) { ThreadState* state = ThreadStateFor<ThreadingTrait<CSSValue>::kAffinity>::GetState(); const char* type_name = "blink::CSSValue"; return state->Heap().AllocateOnArenaIndex( state, size, BlinkGC::kCSSValueArenaIndex, - GCInfoTrait<CSSValue>::Index(), type_name); + GCInfoTrait<GCInfoFoldedType<CSSValue>>::Index(), type_name); } // TODO(sashab): Remove this method and move logic to the caller.
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h index d1c1b97..b79c7d6 100644 --- a/third_party/blink/renderer/core/dom/node.h +++ b/third_party/blink/renderer/core/dom/node.h
@@ -163,15 +163,14 @@ kDocumentPositionImplementationSpecific = 0x20, }; - // Override operator new to allocate Node subtype objects onto - // a dedicated heap. + template <typename T> static void* AllocateObject(size_t size) { ThreadState* state = ThreadStateFor<ThreadingTrait<Node>::kAffinity>::GetState(); const char* type_name = "blink::Node"; return state->Heap().AllocateOnArenaIndex( state, size, BlinkGC::kNodeArenaIndex, - GCInfoTrait<EventTarget>::Index(), type_name); + GCInfoTrait<GCInfoFoldedType<T>>::Index(), type_name); } static void DumpStatistics();
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc index c58ec5f..c13d2ddd 100644 --- a/third_party/blink/renderer/core/layout/hit_test_result.cc +++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -46,8 +46,6 @@ namespace blink { -using namespace html_names; - HitTestResult::HitTestResult() : hit_test_request_(HitTestRequest::kReadOnly | HitTestRequest::kActive), cacheable_(true), @@ -190,7 +188,7 @@ return nullptr; HTMLMapElement* map = image_element->GetTreeScope().GetImageMap( - image_element->FastGetAttribute(kUsemapAttr)); + image_element->FastGetAttribute(html_names::kUsemapAttr)); if (!map) return nullptr; @@ -293,7 +291,7 @@ return g_null_atom; if (auto* image = ToHTMLImageElementOrNull(*inner_node_or_image_map_image)) - return image->getAttribute(kAltAttr); + return image->getAttribute(html_names::kAltAttr); if (auto* input = ToHTMLInputElementOrNull(*inner_node_or_image_map_image)) return input->Alt();
diff --git a/third_party/blink/renderer/core/layout/layout_details_marker.cc b/third_party/blink/renderer/core/layout/layout_details_marker.cc index 190448dd..9b6e044 100644 --- a/third_party/blink/renderer/core/layout/layout_details_marker.cc +++ b/third_party/blink/renderer/core/layout/layout_details_marker.cc
@@ -27,31 +27,22 @@ namespace blink { -using namespace html_names; - LayoutDetailsMarker::LayoutDetailsMarker(Element* element) : LayoutBlockFlow(element) {} LayoutDetailsMarker::Orientation LayoutDetailsMarker::GetOrientation() const { - switch (StyleRef().GetWritingMode()) { - case WritingMode::kHorizontalTb: - if (StyleRef().IsLeftToRightDirection()) - return IsOpen() ? kDown : kRight; - return IsOpen() ? kDown : kLeft; - case WritingMode::kVerticalRl: - if (StyleRef().IsLeftToRightDirection()) - return IsOpen() ? kLeft : kDown; - return IsOpen() ? kLeft : kUp; - case WritingMode::kVerticalLr: - if (StyleRef().IsLeftToRightDirection()) - return IsOpen() ? kRight : kDown; - return IsOpen() ? kRight : kUp; - // TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported. - default: - break; + // TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported. + const auto mode = StyleRef().GetWritingMode(); + DCHECK(mode != WritingMode::kSidewaysRl && mode != WritingMode::kSidewaysLr); + + if (IsOpen()) { + if (mode == WritingMode::kHorizontalTb) + return kDown; + return (mode == WritingMode::kVerticalRl) ? kLeft : kRight; } - NOTREACHED(); - return kRight; + if (mode == WritingMode::kHorizontalTb) + return StyleRef().IsLeftToRightDirection() ? kRight : kLeft; + return StyleRef().IsLeftToRightDirection() ? kDown : kUp; } void LayoutDetailsMarker::Paint(const PaintInfo& paint_info) const { @@ -61,13 +52,12 @@ bool LayoutDetailsMarker::IsOpen() const { for (LayoutObject* layout_object = Parent(); layout_object; layout_object = layout_object->Parent()) { - if (!layout_object->GetNode()) + const auto* node = layout_object->GetNode(); + if (!node) continue; - if (IsHTMLDetailsElement(*layout_object->GetNode())) - return !To<Element>(layout_object->GetNode()) - ->getAttribute(kOpenAttr) - .IsNull(); - if (IsHTMLInputElement(*layout_object->GetNode())) + if (IsHTMLDetailsElement(*node)) + return !To<Element>(node)->getAttribute(html_names::kOpenAttr).IsNull(); + if (IsHTMLInputElement(*node)) return true; }
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc index 71066fd..d4dc838 100644 --- a/third_party/blink/renderer/core/layout/layout_image.cc +++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -50,8 +50,6 @@ namespace blink { -using namespace html_names; - LayoutImage::LayoutImage(Element* element) : LayoutReplaced(element, LayoutSize()), did_increment_visually_non_empty_pixel_count_(false), @@ -287,7 +285,8 @@ HTMLMapElement* LayoutImage::ImageMap() const { HTMLImageElement* i = ToHTMLImageElementOrNull(GetNode()); - return i ? i->GetTreeScope().GetImageMap(i->FastGetAttribute(kUsemapAttr)) + return i ? i->GetTreeScope().GetImageMap( + i->FastGetAttribute(html_names::kUsemapAttr)) : nullptr; }
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc index ce97dd7d..fd11296 100644 --- a/third_party/blink/renderer/core/layout/layout_table_cell.cc +++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -43,8 +43,6 @@ namespace blink { -using namespace html_names; - struct SameSizeAsLayoutTableCell : public LayoutBlockFlow, public LayoutNGTableCellInterface { unsigned bitfields; @@ -203,7 +201,7 @@ // See if nowrap was set. Length w = StyleOrColLogicalWidth(); const AtomicString& nowrap = - To<Element>(GetNode())->getAttribute(kNowrapAttr); + To<Element>(GetNode())->getAttribute(html_names::kNowrapAttr); if (!nowrap.IsNull() && w.IsFixed()) { // Nowrap is set, but we didn't actually use it because of the fixed width // set on the cell. Even so, it is a WinIE/Moz trait to make the minwidth
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc index 9369d73..8022ea04 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -16,6 +16,7 @@ type_(kText), sub_type_(static_cast<unsigned>(text.TextType())), style_variant_(static_cast<unsigned>(text.StyleVariant())), + is_generated_text_(text.IsGeneratedText()), is_hidden_for_paint_(false), text_direction_(static_cast<unsigned>(text.ResolvedDirection())) { DCHECK_LE(text_.start_offset, text_.end_offset); @@ -82,6 +83,13 @@ return false; } +bool NGFragmentItem::IsGeneratedText() const { + if (Type() == kText || Type() == kGeneratedText) + return is_generated_text_; + NOTREACHED(); + return false; +} + PhysicalRect NGFragmentItem::SelfInkOverflow() const { // TODO(kojii): Implement. return LocalRect();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h index 4570ca0..125bdf98 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -238,6 +238,17 @@ return StyleVariant() == NGStyleVariant::kEllipsis; } + // Returns true if the text is generated (from, e.g., list marker, + // pseudo-element, ...) instead of from a DOM text node. + // * CSS content kText + // * ellipsis kGeneratedText + // * first-letter-part kText + // * list marker kGeneratedText + // * soft hyphen kGeneratedText + // TODO(yosin): When we implement |kGeneratedText|, we rename this function + // to avoid confliction with |kGeneratedText|. + bool IsGeneratedText() const; + bool IsSymbolMarker() const { return TextType() == NGTextType::kSymbolMarker; } @@ -324,6 +335,10 @@ unsigned type_ : 2; // ItemType unsigned sub_type_ : 3; // NGTextType unsigned style_variant_ : 2; // NGStyleVariant + // TODO(yosin): We'll remove |is_generated_text_| field when we construct + // |NGFragmentItem| without |NGPhysicalTextFragment| because usage of this + // varaible, IsGeneratedText(), is not hot. + unsigned is_generated_text_ : 1; // NGPhysicalTextFragment::IsGenerated() unsigned is_hidden_for_paint_ : 1; // Note: For |TextItem| and |GeneratedTextItem|, |text_direction_| equals to // |ShapeResult::Direction()|.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc index 92d4f89f..59ca155 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" +#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h" namespace blink { @@ -115,6 +116,12 @@ return false; } +bool NGInlineCursor::HasSoftWrapToNextLine() const { + DCHECK(IsLineBox()); + const NGInlineBreakToken& break_token = CurrentInlineBreakToken(); + return !break_token.IsFinished() && !break_token.IsForcedBreak(); +} + bool NGInlineCursor::IsAtomicInline() const { if (current_paint_fragment_) return current_paint_fragment_->PhysicalFragment().IsAtomicInline(); @@ -133,6 +140,19 @@ return false; } +bool NGInlineCursor::IsGeneratedText() const { + if (current_paint_fragment_) { + if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>( + current_paint_fragment_->PhysicalFragment())) + return text_fragment->IsGeneratedText(); + return false; + } + if (current_item_) + return current_item_->IsGeneratedText(); + NOTREACHED(); + return false; +} + bool NGInlineCursor::IsHiddenForPaint() const { if (current_paint_fragment_) return current_paint_fragment_->PhysicalFragment().IsHiddenForPaint(); @@ -176,6 +196,17 @@ return false; } +bool NGInlineCursor::IsText() const { + if (current_paint_fragment_) + return current_paint_fragment_->PhysicalFragment().IsText(); + if (current_item_) { + return current_item_->Type() == NGFragmentItem::kText || + current_item_->Type() == NGFragmentItem::kGeneratedText; + } + NOTREACHED(); + return false; +} + bool NGInlineCursor::IsBeforeSoftLineBreak() const { if (IsLineBreak()) return false; @@ -248,6 +279,18 @@ return nullptr; } +const NGInlineBreakToken& NGInlineCursor::CurrentInlineBreakToken() const { + DCHECK(IsLineBox()); + if (current_paint_fragment_) { + return To<NGInlineBreakToken>( + *To<NGPhysicalLineBoxFragment>( + current_paint_fragment_->PhysicalFragment()) + .BreakToken()); + } + DCHECK(current_item_); + return *current_item_->InlineBreakToken(); +} + const LayoutObject* NGInlineCursor::CurrentLayoutObject() const { if (current_paint_fragment_) return current_paint_fragment_->GetLayoutObject(); @@ -257,6 +300,12 @@ return nullptr; } +Node* NGInlineCursor::CurrentNode() const { + if (const LayoutObject* layout_object = CurrentLayoutObject()) + return layout_object->GetNode(); + return nullptr; +} + const PhysicalOffset NGInlineCursor::CurrentOffset() const { if (current_paint_fragment_) return current_paint_fragment_->InlineOffsetToContainerBox(); @@ -368,6 +417,9 @@ } void NGInlineCursor::MoveTo(const NGPaintFragment& paint_fragment) { + DCHECK(!fragment_items_); + if (!root_paint_fragment_) + root_paint_fragment_ = paint_fragment.Root(); DCHECK(root_paint_fragment_); DCHECK(paint_fragment.IsDescendantOfNotSelf(*root_paint_fragment_)) << paint_fragment << " " << root_paint_fragment_; @@ -407,6 +459,21 @@ MakeNull(); } +void NGInlineCursor::MoveToFirstLogicalLeaf() { + DCHECK(IsLineBox()); + // TODO(yosin): This isn't correct for mixed Bidi. Fix it. Besides, we + // should compute and store it during layout. + // TODO(yosin): We should check direction of each container instead of line + // box. See also |NGPhysicalLineBoxFragment::LastLogicalLeaf()|. + if (IsLtr(CurrentStyle().Direction())) { + while (TryToMoveToFirstChild()) + continue; + return; + } + while (TryToMoveToLastChild()) + continue; +} + void NGInlineCursor::MoveToLastChild() { DCHECK(CanHaveChildren()); if (!TryToMoveToLastChild()) @@ -474,6 +541,24 @@ MoveToNextItemSkippingChildren(); } +void NGInlineCursor::MoveToPreviousLine() { + DCHECK(IsLineBox()); + if (current_paint_fragment_) { + // TODO(yosin): We should implement |PreviousLineOf()| here. + if (auto* paint_fragment = + NGPaintFragmentTraversal::PreviousLineOf(*current_paint_fragment_)) + return MoveTo(*paint_fragment); + return MakeNull(); + } + if (current_item_) { + do { + MoveToPreviousItem(); + } while (IsNotNull() && !IsLineBox()); + return; + } + NOTREACHED(); +} + bool NGInlineCursor::TryToMoveToFirstChild() { if (!HasChildren()) return false;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h index d92b72a..716d77cb 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
@@ -18,8 +18,10 @@ class LayoutObject; class NGFragmentItem; class NGFragmentItems; +class NGInlineBreakToken; class NGPaintFragment; class NGPhysicalBoxFragment; +class Node; struct PhysicalOffset; struct PhysicalRect; struct PhysicalSize; @@ -73,6 +75,10 @@ // True if fragment at the current position has children. bool HasChildren() const; + // True if current position has soft wrap to next line. It is error to call + // other than line. + bool HasSoftWrapToNextLine() const; + // True if the current position is a atomic inline. It is error to call at // end. bool IsAtomicInline() const; @@ -84,6 +90,10 @@ // True if the current position is an ellipsis. It is error to call at end. bool IsEllipsis() const; + // True if the current position is a generatd text. It is error to call at + // end. + bool IsGeneratedText() const; + // True if the current position is hidden for paint. It is error to call at // end. bool IsHiddenForPaint() const; @@ -94,6 +104,9 @@ // True if the current position is a line break. It is error to call at end. bool IsLineBreak() const; + // True if the current position is a text. It is error to call at end. + bool IsText() const; + // |Current*| functions return an object for the current position. const NGFragmentItem* CurrentItem() const { return current_item_; } const NGPaintFragment* CurrentPaintFragment() const { @@ -104,6 +117,7 @@ TextDirection CurrentBaseDirection() const; const NGPhysicalBoxFragment* CurrentBoxFragment() const; const LayoutObject* CurrentLayoutObject() const; + Node* CurrentNode() const; // Returns text direction of current text or atomic inline. It is error to // call at other than text or atomic inline. Note: <span> doesn't have // reserved direction. @@ -140,6 +154,10 @@ // See also |TryToMoveToFirstChild()|. void MoveToFirstChild(); + // Move to first logical leaf of current line box. If current line box has + // no children, curosr becomes null. + void MoveToFirstLogicalLeaf(); + // Move to last child of current container box. If the current position is // at fragment without children, this cursor points nothing. // See also |TryToMoveToFirstChild()|. @@ -162,6 +180,10 @@ // Same as |MoveToNext| except that this skips children even if they exist. void MoveToNextSkippingChildren(); + // Move the current position to previous line. It is error to call other than + // line box. + void MoveToPreviousLine(); + // Returns true if the current position moves to first child. bool TryToMoveToFirstChild(); @@ -174,6 +196,9 @@ private: using ItemsSpan = base::span<const std::unique_ptr<NGFragmentItem>>; + // Returns break token for line box. It is error to call other than line box. + const NGInlineBreakToken& CurrentInlineBreakToken() const; + // True if current position is descendant or self of |layout_object|. // Note: This function is used for moving cursor in culled inline boxes. bool IsInclusiveDescendantOf(const LayoutObject& layout_object) const;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc index 1e8e176..d6c81850 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
@@ -135,6 +135,88 @@ EXPECT_FALSE(cursor.TryToMoveToFirstChild()); } +TEST_P(NGInlineCursorTest, FirstLastLogicalLeafInSimpleText) { + // TDOO(yosin): Remove <style> once NGFragmentItem don't do culled inline. + InsertStyleElement("b { background: gray; }"); + NGInlineCursor cursor = + SetupCursor("<div id=root><b>first</b><b>middle</b><b>last</b></div>"); + + NGInlineCursor first_logical_leaf(cursor); + first_logical_leaf.MoveToFirstLogicalLeaf(); + EXPECT_EQ("first", ToDebugString(first_logical_leaf)); + + NGInlineCursor last_logical_leaf(cursor); + last_logical_leaf.MoveToLastLogicalLeaf(); + EXPECT_EQ("last", ToDebugString(last_logical_leaf)); +} + +TEST_P(NGInlineCursorTest, FirstLastLogicalLeafInRtlText) { + // TDOO(yosin): Remove <style> once NGFragmentItem don't do culled inline. + InsertStyleElement("b { background: gray; }"); + NGInlineCursor cursor = SetupCursor( + "<bdo id=root dir=rtl style=display:block>" + "<b>first</b><b>middle</b><b>last</b>" + "</bdo>"); + + NGInlineCursor first_logical_leaf(cursor); + first_logical_leaf.MoveToFirstLogicalLeaf(); + EXPECT_EQ("first", ToDebugString(first_logical_leaf)); + + NGInlineCursor last_logical_leaf(cursor); + last_logical_leaf.MoveToLastLogicalLeaf(); + EXPECT_EQ("last", ToDebugString(last_logical_leaf)); +} + +TEST_P(NGInlineCursorTest, FirstLastLogicalLeafInTextAsDeepDescendants) { + // TDOO(yosin): Remove <style> once NGFragmentItem don't do culled inline. + InsertStyleElement("b { background: gray; }"); + NGInlineCursor cursor = SetupCursor( + "<div id=root>" + "<b><b>first</b>ABC</b>" + "<b>middle</b>" + "<b>DEF<b>last</b></b>" + "</div>"); + + NGInlineCursor first_logical_leaf(cursor); + first_logical_leaf.MoveToFirstLogicalLeaf(); + EXPECT_EQ("first", ToDebugString(first_logical_leaf)); + + NGInlineCursor last_logical_leaf(cursor); + last_logical_leaf.MoveToLastLogicalLeaf(); + EXPECT_EQ("last", ToDebugString(last_logical_leaf)); +} + +TEST_P(NGInlineCursorTest, FirstLastLogicalLeafWithInlineBlock) { + InsertStyleElement("b { display: inline-block; }"); + NGInlineCursor cursor = SetupCursor( + "<div id=root>" + "<b id=first>first</b>middle<b id=last>last</b>" + "</div>"); + + NGInlineCursor first_logical_leaf(cursor); + first_logical_leaf.MoveToFirstLogicalLeaf(); + EXPECT_EQ("#first", ToDebugString(first_logical_leaf)) + << "stop at inline-block"; + + NGInlineCursor last_logical_leaf(cursor); + last_logical_leaf.MoveToLastLogicalLeaf(); + EXPECT_EQ("#last", ToDebugString(last_logical_leaf)) + << "stop at inline-block"; +} + +TEST_P(NGInlineCursorTest, FirstLastLogicalLeafWithImages) { + NGInlineCursor cursor = + SetupCursor("<div id=root><img id=first>middle<img id=last></div>"); + + NGInlineCursor first_logical_leaf(cursor); + first_logical_leaf.MoveToFirstLogicalLeaf(); + EXPECT_EQ("#first", ToDebugString(first_logical_leaf)); + + NGInlineCursor last_logical_leaf(cursor); + last_logical_leaf.MoveToLastLogicalLeaf(); + EXPECT_EQ("#last", ToDebugString(last_logical_leaf)); +} + TEST_P(NGInlineCursorTest, LastChild) { // TDOO(yosin): Remove <style> once NGFragmentItem don't do culled inline. InsertStyleElement("a, b { background: gray; }"); @@ -285,4 +367,25 @@ EXPECT_THAT(list, ElementsAre()); } +TEST_P(NGInlineCursorTest, PreviousLine) { + NGInlineCursor cursor = SetupCursor("<div id=root>abc<br>xyz</div>"); + NGInlineCursor line1(cursor); + while (line1 && !line1.IsLineBox()) + line1.MoveToNext(); + ASSERT_TRUE(line1.IsNotNull()); + NGInlineCursor line2(line1); + line2.MoveToNext(); + while (line2 && !line2.IsLineBox()) + line2.MoveToNext(); + ASSERT_NE(line1, line2); + + NGInlineCursor should_be_null(line1); + should_be_null.MoveToPreviousLine(); + EXPECT_TRUE(should_be_null.IsNull()); + + NGInlineCursor should_be_line1(line2); + should_be_line1.MoveToPreviousLine(); + EXPECT_EQ(line1, should_be_line1); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h index 251ad126..8960f5b 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -233,24 +233,8 @@ // returned. bool FinalizeForFragmentation(); - // Insert a fragmentainer break before the child if necessary. In that case, - // the previous in-flow position will be updated, we'll return |kBrokeBefore|. - // If we don't break inside, we'll consider the appeal of doing so anyway (and - // store it as the most appealing break point so far if that's the case), - // since we might have to go back and break here. Return |kContinue| if we're - // to continue laying out. If |kNeedsEarlierBreak| is returned, it means that - // we ran out of space, but shouldn't break before the child, but rather abort - // layout, and re-layout to a previously found good breakpoint. If - // |has_container_separation| is true, it means that we're at a valid - // breakpoint. We obviously prefer valid breakpoints, but sometimes we need to - // break at undesirable locations. Class A breakpoints occur between block - // siblings. Class B breakpoints between line boxes. Both these breakpoint - // classes imply that we're already past the first in-flow child in the - // container, but there's also another way of achieving container separation: - // class C breakpoints. Those occur if there's a positive gap between the - // block-start content edge of the container and the block-start margin edge - // of the first in-flow child. This can happen when in-flow content is pushed - // down by floats. https://www.w3.org/TR/css-break-3/#possible-breaks + // Insert a fragmentainer break before the child if necessary. + // See |::blink::BreakBeforeChildIfNeeded()| for more documentation. NGBreakStatus BreakBeforeChildIfNeeded(NGLayoutInputNode child, const NGLayoutResult&, NGPreviousInflowPosition*,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h index bc035d1..d0dd84a 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -200,6 +200,10 @@ break_appeal_ = appeal; } bool HasEarlyBreak() const { return early_break_.get(); } + const NGEarlyBreak& EarlyBreak() const { + DCHECK(early_break_.get()); + return *early_break_.get(); + } // Set the highest break appeal found so far. This is either: // 1: The highest appeal of a breakpoint found by our container
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc index 466e4d6..1be5b7d8 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -62,6 +62,17 @@ return broken_node.IsColumnSpanAll() && broken_node != multicol_container; } +// Add the break token for the column content that comes after a fragmented +// spanner, if any; otherwise, we're past all children. +void PushNextColumnBreakToken( + scoped_refptr<const NGBlockBreakToken> next_column_token, + NGBoxFragmentBuilder* builder) { + if (next_column_token) + builder->AddBreakToken(std::move(next_column_token)); + else + builder->SetHasSeenAllChildren(); +} + // Add the spanner's break token, AND another break token for the column content // that comes after. In the next fragment we need to resume layout of the // spanner, and then proceed to the column content - if there's room for both. @@ -71,10 +82,7 @@ scoped_refptr<const NGBlockBreakToken> next_column_token, NGBoxFragmentBuilder* builder) { builder->AddBreakToken(std::move(spanner_break_token)); - if (next_column_token) - builder->AddBreakToken(std::move(next_column_token)); - else - builder->SetHasSeenAllChildren(); + PushNextColumnBreakToken(std::move(next_column_token), builder); } } // namespace @@ -82,6 +90,7 @@ NGColumnLayoutAlgorithm::NGColumnLayoutAlgorithm( const NGLayoutAlgorithmParams& params) : NGLayoutAlgorithm(params), + early_break_(params.early_break), border_padding_(params.fragment_geometry.border + params.fragment_geometry.padding), border_scrollbar_padding_(border_padding_ + @@ -130,7 +139,11 @@ if (!IsResumingLayout(BreakToken())) intrinsic_block_size_ = border_scrollbar_padding_.block_start; - LayoutChildren(); + if (!LayoutChildren()) { + // We need to discard this layout and do it again. We found an earlier break + // point that's more appealing than the one we ran out of space at. + return RelayoutAndBreakEarlier(); + } // Figure out how much space we've already been able to process in previous // fragments, if this multicol container participates in an outer @@ -212,7 +225,7 @@ return sizes; } -void NGColumnLayoutAlgorithm::LayoutChildren() { +bool NGColumnLayoutAlgorithm::LayoutChildren() { NGMarginStrut margin_strut; // First extract incoming child break tokens. @@ -258,20 +271,28 @@ // The multicol container previously broke at a spanner (this may happen if // we're nested inside another fragmentation context), so that's where we'll // resume now. - spanner_break_token = - LayoutSpanner(To<NGBlockNode>(spanner_break_token->InputNode()), - spanner_break_token.get(), &margin_strut); + NGBreakStatus break_status = LayoutSpanner( + To<NGBlockNode>(spanner_break_token->InputNode()), + spanner_break_token.get(), &margin_strut, &spanner_break_token); if (spanner_break_token) { - // We broke at the spanner again! - PushSpannerBreakTokens(std::move(spanner_break_token), - std::move(next_column_token), &container_builder_); - return; + DCHECK_EQ(break_status, NGBreakStatus::kContinue); + if (spanner_break_token) { + // We broke at the spanner again! + PushSpannerBreakTokens(std::move(spanner_break_token), + std::move(next_column_token), + &container_builder_); + return true; + } + } else { + // Breaking before the first element in the fragmentainer isn't allowed, + // as that would give no content progress, and we'd be stuck forever. + DCHECK_EQ(break_status, NGBreakStatus::kContinue); } } if (BreakToken() && BreakToken()->HasSeenAllChildren() && !next_column_token) - return; + return true; // Entering the child main loop. Here we'll alternate between laying out // column content and column spanners, until we're either done, or until @@ -291,18 +312,41 @@ if (!spanner_node) break; - // We found a spanner. Lay it out, and then resume column layout. - spanner_break_token = LayoutSpanner(spanner_node, nullptr, &margin_strut); + if (early_break_) { + // If this is the child we had previously determined to break before, do + // so now and finish layout. + DCHECK_EQ(early_break_->Type(), NGEarlyBreak::kBlock); + if (early_break_->IsBreakBefore() && + early_break_->BlockNode() == spanner_node) { + container_builder_.AddBreakBeforeChild( + spanner_node, kBreakAppealPerfect, /* is_forced_break */ false); + FinishAfterBreakBeforeSpanner(std::move(next_column_token)); + return true; + } + } - if (spanner_break_token) { - // We broke before or inside the spanner. This may happen if we're nested - // inside another fragmentation context. + // We found a spanner. Lay it out, and then resume column layout. + NGBreakStatus break_status = LayoutSpanner( + spanner_node, nullptr, &margin_strut, &spanner_break_token); + if (break_status == NGBreakStatus::kNeedsEarlierBreak) { + return false; + } else if (break_status == NGBreakStatus::kBrokeBefore) { + DCHECK(ConstraintSpace().HasBlockFragmentation()); + FinishAfterBreakBeforeSpanner(std::move(next_column_token)); + return true; + } else if (spanner_break_token) { + DCHECK_EQ(break_status, NGBreakStatus::kContinue); + // We broke inside the spanner. This may happen if we're nested inside + // another fragmentation context. PushSpannerBreakTokens(std::move(spanner_break_token), std::move(next_column_token), &container_builder_); - return; + return true; } } while (next_column_token); + // If there's an early break set, we should have found it and returned. + DCHECK(!early_break_); + if (next_column_token) { // We broke inside column content. Add a break token for where to resume // column layout at in the next fragment. @@ -318,6 +362,8 @@ intrinsic_block_size_ += margin_strut.Sum(); } + + return true; } scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow( @@ -511,7 +557,7 @@ break; } while (true); - bool keep_margin = false; + bool is_empty = false; // If there was no content inside to process, we don't want the resulting // empty column fragment. @@ -521,7 +567,7 @@ if (column.Children().size() == 0) { // No content. Keep the trailing margin from any previous column spanner. - keep_margin = true; + is_empty = true; // TODO(mstensho): It's wrong to keep the empty fragment, just so that // out-of-flow descendants get propagated correctly. Find some other way @@ -533,9 +579,14 @@ intrinsic_block_size_ = column_block_offset + column_size.block_size; - // We added a row. Reset the trailing margin from any previous column spanner. - if (!keep_margin) + if (!is_empty) { + has_processed_first_child_ = true; + container_builder_.SetPreviousBreakAfter(EBreakBetween::kAuto); + + // We added a row. Reset the trailing margin from any previous column + // spanner. *margin_strut = NGMarginStrut(); + } // Commit all column fragments to the fragment builder. for (auto column : new_columns) { @@ -546,20 +597,23 @@ return result; } -scoped_refptr<const NGBlockBreakToken> NGColumnLayoutAlgorithm::LayoutSpanner( +NGBreakStatus NGColumnLayoutAlgorithm::LayoutSpanner( NGBlockNode spanner_node, const NGBlockBreakToken* break_token, - NGMarginStrut* margin_strut) { + NGMarginStrut* margin_strut, + scoped_refptr<const NGBlockBreakToken>* spanner_break_token) { + *spanner_break_token = nullptr; const ComputedStyle& spanner_style = spanner_node.Style(); NGBoxStrut margins = ComputeMarginsFor( spanner_style, content_box_size_.inline_size, ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction()); if (break_token) { - // Truncate block-start margins at fragmentainer breaks, and also make sure - // that we don't repeat them at the beginning of every fragment generated - // from the spanner node. - margins.block_start = LayoutUnit(); + // Truncate block-start margins at fragmentainer breaks (except when the + // break is forced), and also make sure that we don't repeat them at the + // beginning of every fragment generated from the spanner node. + if (!break_token->IsBreakBefore() || !break_token->IsForcedBreak()) + margins.block_start = LayoutUnit(); if (break_token->IsBreakBefore()) { // TODO(mstensho): Passing a break-before token shouldn't be a problem, @@ -573,12 +627,42 @@ // of an immediately preceding spanner, if any. margin_strut->Append(margins.block_start, /* is_quirky */ false); - // TODO(mstensho): outer fragmentainer breaks between spanners and rows (the - // spanner may be unbreakable inside, and we may be in a nested fragmentation - // context and out of space). LayoutUnit block_offset = intrinsic_block_size_ + margin_strut->Sum(); auto spanner_space = CreateConstraintSpaceForSpanner(block_offset); - auto result = spanner_node.Layout(spanner_space, break_token); + + const NGEarlyBreak* early_break_in_child = nullptr; + if (early_break_ && early_break_->Type() == NGEarlyBreak::kBlock && + early_break_->BlockNode() == spanner_node) { + // We're entering a child that we know that we're going to break inside, and + // even where to break. Look inside, and pass the inner breakpoint to + // layout. + early_break_in_child = early_break_->BreakInside(); + // If there's no break inside, we should already have broken before this + // child. + DCHECK(early_break_in_child); + } + + auto result = + spanner_node.Layout(spanner_space, break_token, early_break_in_child); + + if (ConstraintSpace().HasBlockFragmentation() && !early_break_) { + // We're nested inside another fragmentation context. Examine this break + // point, and determine whether we should break. + + LayoutUnit fragmentainer_block_offset = + ConstraintSpace().FragmentainerOffsetAtBfc() + block_offset; + + NGBreakStatus break_status = BreakBeforeChildIfNeeded( + ConstraintSpace(), spanner_node, *result.get(), + fragmentainer_block_offset, has_processed_first_child_, + &container_builder_); + + if (break_status != NGBreakStatus::kContinue) { + // We need to break, either before the spanner, or even earlier. + return break_status; + } + } + NGFragment fragment(ConstraintSpace().GetWritingMode(), result->PhysicalFragment()); @@ -593,18 +677,16 @@ *margin_strut = NGMarginStrut(); margin_strut->Append(margins.block_end, /* is_quirky */ false); - // TODO(mstensho): The correct thing would be to weigh any break inside - // against the appeal of breaking before the spanner, like we do in - // BreakBeforeChildIfNeeded() for the block layout algorithm. Just setting the - // appeal to perfect isn't right, but we're doing it for now, so that any - // break inside the spanner (in case we're nested inside another fragmentation - // context) isn't just discarded. - if (ConstraintSpace().HasBlockFragmentation()) - container_builder_.SetBreakAppeal(kBreakAppealPerfect); - intrinsic_block_size_ = offset.block_offset + fragment.BlockSize(); + has_processed_first_child_ = true; - return To<NGBlockBreakToken>(result->PhysicalFragment().BreakToken()); + EBreakBetween break_after = JoinFragmentainerBreakValues( + result->FinalBreakAfter(), spanner_node.Style().BreakAfter()); + container_builder_.SetPreviousBreakAfter(break_after); + + *spanner_break_token = + To<NGBlockBreakToken>(result->PhysicalFragment().BreakToken()); + return NGBreakStatus::kContinue; } LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize( @@ -784,6 +866,39 @@ return intrinsic_block_size_ - border_scrollbar_padding_.block_start; } +void NGColumnLayoutAlgorithm::FinishAfterBreakBeforeSpanner( + scoped_refptr<const NGBlockBreakToken> next_column_token) { + // We broke before the spanner. We're done here. Take up the remaining space + // in the outer fragmentation context. + intrinsic_block_size_ = FragmentainerSpaceAtBfcStart(ConstraintSpace()); + + // A break token for the spanner has already been inserted, but we also need + // to add one for the column contents that follows, so that we know where to + // resume, once done with the spanner - or - specify that we're past + // everything if there's nothing to resume at (so that we don't restart from + // the beginning of the multicol container). + PushNextColumnBreakToken(std::move(next_column_token), &container_builder_); +} + +scoped_refptr<const NGLayoutResult> +NGColumnLayoutAlgorithm::RelayoutAndBreakEarlier() { + // Not allowed to recurse! + DCHECK(!early_break_); + + const NGEarlyBreak& breakpoint = container_builder_.EarlyBreak(); + NGLayoutAlgorithmParams params(Node(), + container_builder_.InitialFragmentGeometry(), + ConstraintSpace(), BreakToken(), &breakpoint); + NGColumnLayoutAlgorithm algorithm_with_break(params); + NGBoxFragmentBuilder& new_builder = algorithm_with_break.container_builder_; + new_builder.SetBoxType(container_builder_.BoxType()); + // We're not going to run out of space in the next layout pass, since we're + // breaking earlier, so no space shortage will be detected. Repeat what we + // found in this pass. + new_builder.PropagateSpaceShortage(container_builder_.MinimalSpaceShortage()); + return algorithm_with_break.Layout(); +} + NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForColumns( const LogicalSize& column_size, bool is_first_fragmentainer,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h index 5707f83..42b5e9d8 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -10,6 +10,7 @@ namespace blink { +enum class NGBreakStatus; class NGBlockNode; class NGBlockBreakToken; class NGConstraintSpace; @@ -29,8 +30,10 @@ const MinMaxSizeInput&) const override; private: - // Lay out as many children as we can. - void LayoutChildren(); + // Lay out as many children as we can. If false is returned, it means that we + // ran out of space at an unappealing location, and need to relayout and break + // earlier (because we have a better breakpoint there). + bool LayoutChildren(); // Lay out one row of columns. The layout result returned is for the last // column that was laid out. The rows themselves don't create fragments. @@ -38,13 +41,16 @@ const NGBlockBreakToken* next_column_token, NGMarginStrut*); - // Lay out a column spanner. Will return a break token if we break before or - // inside the spanner. If no break token is returned, it means that we can - // proceed to the next row of columns. - scoped_refptr<const NGBlockBreakToken> LayoutSpanner( - NGBlockNode spanner_node, - const NGBlockBreakToken* break_token, - NGMarginStrut*); + // Lay out a column spanner. The return value will tell whether to break + // before the spanner or not. If we're not to break before the spanner, but + // rather inside, |spanner_break_token| will be set, so that we know where to + // resume in the next outer fragmentainer. If |NGBreakStatus::kContinue| is + // returned, and no break token was set, it means that we can proceed to the + // next row of columns. + NGBreakStatus LayoutSpanner(NGBlockNode spanner_node, + const NGBlockBreakToken* break_token, + NGMarginStrut*, + scoped_refptr<const NGBlockBreakToken>*); LayoutUnit CalculateBalancedColumnBlockSize( const LogicalSize& column_size, @@ -58,6 +64,16 @@ LayoutUnit ConstrainColumnBlockSize(LayoutUnit size) const; LayoutUnit CurrentContentBlockOffset() const; + // Finalize layout after breaking before a spanner. + void FinishAfterBreakBeforeSpanner( + scoped_refptr<const NGBlockBreakToken> next_column_token); + + // Lay out again, this time with a predefined good breakpoint that we + // discovered in the first pass. This happens when we run out of space in a + // fragmentainer at an less-than-ideal location, due to breaking restrictions, + // such as break-before:avoid or break-after:avoid. + scoped_refptr<const NGLayoutResult> RelayoutAndBreakEarlier(); + NGConstraintSpace CreateConstraintSpaceForColumns( const LogicalSize& column_size, bool is_first_fragmentainer, @@ -68,6 +84,9 @@ LayoutUnit block_offset) const; NGConstraintSpace CreateConstraintSpaceForMinMax() const; + // When set, this will specify where to break before or inside. + const NGEarlyBreak* early_break_ = nullptr; + const NGBoxStrut border_padding_; const NGBoxStrut border_scrollbar_padding_; LogicalSize content_box_size_; @@ -76,6 +95,11 @@ LayoutUnit column_inline_progression_; LayoutUnit intrinsic_block_size_; bool is_constrained_by_outer_fragmentation_context_ = false; + + // This will be set during (outer) block fragmentation once we've processed + // the first piece of content of the multicol container. It is used to check + // if we're at a valid class A breakpoint (between block-level siblings). + bool has_processed_first_child_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc index e5de35ad..07118b1 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -4672,6 +4672,424 @@ EXPECT_EQ(expectation, dump); } +TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners) { + // There are two spanners in a nested multicol. They could fit in the same + // outer column, but there's a forced break between them. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> + <div style="column-span:all; break-before:column; break-inside:avoid; width:66px; height:40px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x40 + offset:110,0 size:100x40 + offset:0,0 size:100x40 + offset:0,0 size:66x40 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners2) { + // There are two spanners in a nested multicol. They could fit in the same + // outer column, but there's a forced break between them. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-after:column; break-inside:avoid; width:55px; height:40px;"></div> + <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x40 + offset:110,0 size:100x40 + offset:0,0 size:100x40 + offset:0,0 size:66x40 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners3) { + // There are two spanners in a nested multicol. They could fit in the same + // outer column, but there's a forced break after the last child of the first + // spanner. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"> + <div style="width:33px; height:10px;"></div> + <div style="break-after:column; width:44px; height:10px;"></div> + </div> + <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x40 + offset:0,0 size:33x10 + offset:0,10 size:44x10 + offset:110,0 size:100x40 + offset:0,0 size:100x40 + offset:0,0 size:66x40 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners4) { + // There are two spanners in a nested multicol. They could fit in the same + // outer column, but there's a forced break before the first child of the + // last spanner. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> + <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"> + <div style="break-before:column; width:33px; height:10px;"></div> + <div style="width:44px; height:10px;"></div> + </div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x40 + offset:110,0 size:100x40 + offset:0,0 size:100x40 + offset:0,0 size:66x40 + offset:0,0 size:33x10 + offset:0,10 size:44x10 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners5) { + // There are two spanners in a nested multicol. They could fit in the same + // outer column, but there's a forced break between them. The second spanner + // has a top margin, which should be retained, due to the forced break. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> + <div style="column-span:all; break-before:column; break-inside:avoid; width:66px; height:40px; margin-top:10px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x40 + offset:110,0 size:100x50 + offset:0,0 size:100x50 + offset:0,10 size:66x40 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenSpanners) { + // There are two spanners in a nested multicol. They won't fit in the same + // outer column, and we don't want to break inside. So we should break between + // them. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:60px;"></div> + <div style="column-span:all; break-inside:avoid; width:66px; height:60px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x60 + offset:110,0 size:100x60 + offset:0,0 size:100x60 + offset:0,0 size:66x60 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenSpanners2) { + // There are two spanners in a nested multicol. They won't fit in the same + // outer column, and we don't want to break inside. So we should break between + // them. The second spanner has a top margin, but it should be truncated since + // it's at a soft break. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:60px;"></div> + <div style="column-span:all; break-inside:avoid; width:66px; height:60px; margin-top:10px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x60 + offset:110,0 size:100x60 + offset:0,0 size:100x60 + offset:0,0 size:66x60 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners) { + // There are three spanners in a nested multicol. The first two could fit in + // the same outer column, but the third one is too tall, and we also don't + // want to break before that one.So we should break between the two first + // spanners. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> + <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"></div> + <div style="column-span:all; break-inside:avoid; break-before:avoid; width:77px; height:60px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:55x40 + offset:110,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:66x40 + offset:0,40 size:77x60 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners2) { + // There are two spanners in a nested multicol. They won't fit in the same + // outer column, but we don't want to break inside the second one, and also + // not between the spanners. The first spanner is breakable, so we should + // break at the most appealing breakpoint there, i.e. before its last child. + SetBodyInnerHTML(R"HTML( + <style> + .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } + .inner { columns:2; } + .content { break-inside:avoid; height:20px; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; width:11px;"> + <div class="content" style="width:22px;"></div> + <div class="content" style="width:33px;"></div> + <div class="content" style="width:44px;"></div> + </div> + <div style="column-span:all; break-inside:avoid; break-before:avoid; width:55px; height:60px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:11x100 + offset:0,0 size:22x20 + offset:0,20 size:33x20 + offset:110,0 size:100x80 + offset:0,0 size:100x80 + offset:0,0 size:11x20 + offset:0,0 size:44x20 + offset:0,20 size:55x60 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners3) { + // Violate orphans and widows requests rather than break-between avoidance + // requests. + SetBodyInnerHTML(R"HTML( + <style> + .outer { + columns:3; + height:100px; + column-fill:auto; + column-gap:10px; + width:320px; + line-height: 20px; + orphans: 3; + widows: 3; + } + .inner { columns:2; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div style="column-span:all; width:11px;"> + <br> + <br> + <br> + </div> + <div style="column-span:all; break-inside:avoid; break-before:avoid; width:55px; height:60px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:11x100 + offset:0,0 size:0x20 + offset:0,9 size:0x1 + offset:0,20 size:0x20 + offset:0,9 size:0x1 + offset:110,0 size:100x80 + offset:0,0 size:100x80 + offset:0,0 size:11x20 + offset:0,0 size:0x20 + offset:0,9 size:0x1 + offset:0,20 size:55x60 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenRowAndSpanner) { + // We have a nested multicol with some column content, followed by a + // spanner. Everything won't fit in the same outer column, and we don't want + // to break inside the spanner. Break between the row of columns and the + // spanner. + SetBodyInnerHTML(R"HTML( + <style> + .outer { + columns:3; + height:100px; + column-fill:auto; + column-gap:10px; + width:320px; + } + .inner { columns:2; column-gap:10px; } + .content { break-inside:avoid; height:20px; } + </style> + <div id="container"> + <div class="outer"> + <div class="inner"> + <div class="content" style="width:11px;"></div> + <div class="content" style="width:22px;"></div> + <div class="content" style="width:33px;"></div> + <div style="column-span:all; break-inside:avoid; width:44px; height:70px;"></div> + </div> + </div> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x100 + offset:0,0 size:320x100 + offset:0,0 size:100x100 + offset:0,0 size:100x100 + offset:0,0 size:45x40 + offset:0,0 size:11x20 + offset:0,20 size:22x20 + offset:55,0 size:45x20 + offset:0,0 size:33x20 + offset:110,0 size:100x70 + offset:0,0 size:100x70 + offset:0,0 size:44x70 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + TEST_F(NGColumnLayoutAlgorithmTest, SpannerAsMulticol) { SetBodyInnerHTML(R"HTML( <style>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc index d0b3b243..e1d3a77 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -213,6 +213,44 @@ builder->SetIntrinsicBlockSize(intrinsic_block_size); } +NGBreakStatus BreakBeforeChildIfNeeded(const NGConstraintSpace& space, + NGLayoutInputNode child, + const NGLayoutResult& layout_result, + LayoutUnit fragmentainer_block_offset, + bool has_container_separation, + NGBoxFragmentBuilder* builder) { + DCHECK(space.HasBlockFragmentation()); + + if (has_container_separation) { + EBreakBetween break_between = + CalculateBreakBetweenValue(child, layout_result, *builder); + if (IsForcedBreakValue(space, break_between)) { + BreakBeforeChild(space, child, layout_result, fragmentainer_block_offset, + kBreakAppealPerfect, /* is_forced_break */ true, + builder); + return NGBreakStatus::kBrokeBefore; + } + } + + NGBreakAppeal appeal_before = CalculateBreakAppealBefore( + space, child, layout_result, *builder, has_container_separation); + + // Attempt to move past the break point, and if we can do that, also assess + // the appeal of breaking there, even if we didn't. + if (MovePastBreakpoint(space, child, layout_result, + fragmentainer_block_offset, appeal_before, builder)) + return NGBreakStatus::kContinue; + + // Breaking inside the child isn't appealing, and we're out of space. Figure + // out where to insert a soft break. It will either be before this child, or + // before an earlier sibling, if there's a more appealing breakpoint there. + if (!AttemptSoftBreak(space, child, layout_result, fragmentainer_block_offset, + appeal_before, builder)) + return NGBreakStatus::kNeedsEarlierBreak; + + return NGBreakStatus::kBrokeBefore; +} + void BreakBeforeChild(const NGConstraintSpace& space, NGLayoutInputNode child, const NGLayoutResult& layout_result,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h index 8fb3ade..c8ac752 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h +++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -109,6 +109,30 @@ kNeedsEarlierBreak }; +// Insert a fragmentainer break before the child if necessary. In that case, the +// previous in-flow position will be updated, we'll return |kBrokeBefore|. If we +// don't break inside, we'll consider the appeal of doing so anyway (and store +// it as the most appealing break point so far if that's the case), since we +// might have to go back and break here. Return |kContinue| if we're to continue +// laying out. If |kNeedsEarlierBreak| is returned, it means that we ran out of +// space, but shouldn't break before the child, but rather abort layout, and +// re-layout to a previously found good breakpoint. If +// |has_container_separation| is true, it means that we're at a valid +// breakpoint. We obviously prefer valid breakpoints, but sometimes we need to +// break at undesirable locations. Class A breakpoints occur between block +// siblings. Class B breakpoints between line boxes. Both these breakpoint +// classes imply that we're already past the first in-flow child in the +// container, but there's also another way of achieving container separation: +// class C breakpoints. Those occur if there's a positive gap between the +// block-start content edge of the container and the block-start margin edge of +// the first in-flow child. https://www.w3.org/TR/css-break-3/#possible-breaks +NGBreakStatus BreakBeforeChildIfNeeded(const NGConstraintSpace&, + NGLayoutInputNode child, + const NGLayoutResult&, + LayoutUnit fragmentainer_block_offset, + bool has_container_separation, + NGBoxFragmentBuilder*); + // Insert a break before the child, and propagate space shortage if needed. void BreakBeforeChild(const NGConstraintSpace&, NGLayoutInputNode child,
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/third_party/blink/renderer/core/layout/svg/svg_resources.cc index 32620578..a2a132c 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -43,8 +43,6 @@ namespace blink { -using namespace svg_names; - SVGResources::SVGResources() : linked_resource_(nullptr) {} SVGResourceClient* SVGResources::GetClient(const LayoutObject& object) { @@ -59,26 +57,28 @@ // http://www.w3.org/TR/SVG11/intro.html#TermContainerElement // "graphics elements" : // http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement - kATag.LocalName(), kCircleTag.LocalName(), kEllipseTag.LocalName(), - kGTag.LocalName(), kImageTag.LocalName(), kLineTag.LocalName(), - kMarkerTag.LocalName(), kMaskTag.LocalName(), kPathTag.LocalName(), - kPolygonTag.LocalName(), kPolylineTag.LocalName(), - kRectTag.LocalName(), kSVGTag.LocalName(), kTextTag.LocalName(), - kUseTag.LocalName(), + svg_names::kATag.LocalName(), svg_names::kCircleTag.LocalName(), + svg_names::kEllipseTag.LocalName(), svg_names::kGTag.LocalName(), + svg_names::kImageTag.LocalName(), svg_names::kLineTag.LocalName(), + svg_names::kMarkerTag.LocalName(), svg_names::kMaskTag.LocalName(), + svg_names::kPathTag.LocalName(), svg_names::kPolygonTag.LocalName(), + svg_names::kPolylineTag.LocalName(), svg_names::kRectTag.LocalName(), + svg_names::kSVGTag.LocalName(), svg_names::kTextTag.LocalName(), + svg_names::kUseTag.LocalName(), // Not listed in the definitions is the clipPath element, the SVG spec // says though: // The "clipPath" element or any of its children can specify property // "clip-path". // So we have to add kClipPathTag here, otherwhise clip-path on // clipPath will fail. (Already mailed SVG WG, waiting for a solution) - kClipPathTag.LocalName(), + svg_names::kClipPathTag.LocalName(), // Not listed in the definitions are the text content elements, though // filter/clipper/masker on tspan/text/.. is allowed. // (Already mailed SVG WG, waiting for a solution) - kTextPathTag.LocalName(), kTSpanTag.LocalName(), + svg_names::kTextPathTag.LocalName(), svg_names::kTSpanTag.LocalName(), // Not listed in the definitions is the foreignObject element, but // clip-path is a supported attribute. - kForeignObjectTag.LocalName(), + svg_names::kForeignObjectTag.LocalName(), // Elements that we ignore, as it doesn't make any sense. // defs, pattern, switch (FIXME: Mail SVG WG about these) // symbol (is converted to a svg element, when referenced by use, we @@ -90,21 +90,28 @@ bool SVGResources::SupportsMarkers(const SVGElement& element) { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list, ({ - kLineTag.LocalName(), kPathTag.LocalName(), - kPolygonTag.LocalName(), kPolylineTag.LocalName(), + svg_names::kLineTag.LocalName(), + svg_names::kPathTag.LocalName(), + svg_names::kPolygonTag.LocalName(), + svg_names::kPolylineTag.LocalName(), })); return tag_list.Contains(element.localName()); } static HashSet<AtomicString>& FillAndStrokeTags() { - DEFINE_STATIC_LOCAL( - HashSet<AtomicString>, tag_list, - ({ - kCircleTag.LocalName(), kEllipseTag.LocalName(), kLineTag.LocalName(), - kPathTag.LocalName(), kPolygonTag.LocalName(), - kPolylineTag.LocalName(), kRectTag.LocalName(), kTextTag.LocalName(), - kTextPathTag.LocalName(), kTSpanTag.LocalName(), - })); + DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list, + ({ + svg_names::kCircleTag.LocalName(), + svg_names::kEllipseTag.LocalName(), + svg_names::kLineTag.LocalName(), + svg_names::kPathTag.LocalName(), + svg_names::kPolygonTag.LocalName(), + svg_names::kPolylineTag.LocalName(), + svg_names::kRectTag.LocalName(), + svg_names::kTextTag.LocalName(), + svg_names::kTextPathTag.LocalName(), + svg_names::kTSpanTag.LocalName(), + })); return tag_list; }
diff --git a/third_party/blink/renderer/core/loader/form_submission.cc b/third_party/blink/renderer/core/loader/form_submission.cc index d5e9b38..ea1f3f75 100644 --- a/third_party/blink/renderer/core/loader/form_submission.cc +++ b/third_party/blink/renderer/core/loader/form_submission.cc
@@ -52,8 +52,6 @@ namespace blink { -using namespace html_names; - static int64_t GenerateFormDataIdentifier() { // Initialize to the current time to reduce the likelihood of generating // identifiers that overlap with those from past/future browser sessions. @@ -183,16 +181,20 @@ copied_attributes.CopyFrom(attributes); if (submit_button) { AtomicString attribute_value; - if (!(attribute_value = submit_button->FastGetAttribute(kFormactionAttr)) + if (!(attribute_value = + submit_button->FastGetAttribute(html_names::kFormactionAttr)) .IsNull()) copied_attributes.ParseAction(attribute_value); - if (!(attribute_value = submit_button->FastGetAttribute(kFormenctypeAttr)) + if (!(attribute_value = + submit_button->FastGetAttribute(html_names::kFormenctypeAttr)) .IsNull()) copied_attributes.UpdateEncodingType(attribute_value); - if (!(attribute_value = submit_button->FastGetAttribute(kFormmethodAttr)) + if (!(attribute_value = + submit_button->FastGetAttribute(html_names::kFormmethodAttr)) .IsNull()) copied_attributes.UpdateMethodType(attribute_value); - if (!(attribute_value = submit_button->FastGetAttribute(kFormtargetAttr)) + if (!(attribute_value = + submit_button->FastGetAttribute(html_names::kFormtargetAttr)) .IsNull()) copied_attributes.SetTarget(attribute_value); }
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index 8d19bd7..39ca1d2 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -123,8 +123,6 @@ namespace blink { -using namespace html_names; - bool IsBackForwardLoadType(WebFrameLoadType type) { return type == WebFrameLoadType::kBackForward; }
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc index adeed97..7389a37 100644 --- a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc +++ b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -36,7 +36,7 @@ namespace blink { -using namespace html_names; +using html_names::kStyleAttr; // NOTE: This test uses <iframe sandbox> to create cross origin iframes. @@ -285,7 +285,7 @@ // TODO(skyostil): these expectations are either wrong, or the test is // not exercising the code correctly. PaintClean means the entire lifecycle // ran. - frame_element->setAttribute(kWidthAttr, "50"); + frame_element->setAttribute(html_names::kWidthAttr, "50"); CompositeFrame(); if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc index 314bd14..3beacf21d 100644 --- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc +++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -298,7 +298,6 @@ ClearResourceAndEventBaseReferences(); ClearConditions(); SetTargetElement(nullptr); - AnimationAttributeChanged(); time_container_ = nullptr; } @@ -483,7 +482,6 @@ time_container_->ScheduleIntervalUpdate(); } } - AnimationAttributeChanged(); } else if (name == svg_names::kEndAttr) { if (!conditions_.IsEmpty()) { ClearConditions(); @@ -499,7 +497,6 @@ time_container_->ScheduleIntervalUpdate(); } } - AnimationAttributeChanged(); } else if (name == svg_names::kOnbeginAttr) { SetAttributeEventListener(event_type_names::kBeginEvent, CreateAttributeEventListener(this, name, value)); @@ -518,34 +515,31 @@ restart_ = kRestartAlways; } else if (name == svg_names::kFillAttr) { fill_ = value == "freeze" ? kFillFreeze : kFillRemove; + } else if (name == svg_names::kDurAttr) { + cached_dur_ = kInvalidCachedTime; + } else if (name == svg_names::kRepeatDurAttr) { + cached_repeat_dur_ = kInvalidCachedTime; + } else if (name == svg_names::kRepeatCountAttr) { + cached_repeat_count_ = SMILRepeatCount::Invalid(); + } else if (name == svg_names::kMinAttr) { + cached_min_ = kInvalidCachedTime; + } else if (name == svg_names::kMaxAttr) { + cached_max_ = kInvalidCachedTime; } else { SVGElement::ParseAttribute(params); } } void SVGSMILElement::SvgAttributeChanged(const QualifiedName& attr_name) { - if (attr_name == svg_names::kDurAttr) { - cached_dur_ = kInvalidCachedTime; - } else if (attr_name == svg_names::kRepeatDurAttr) { - cached_repeat_dur_ = kInvalidCachedTime; - } else if (attr_name == svg_names::kRepeatCountAttr) { - cached_repeat_count_ = SMILRepeatCount::Invalid(); - } else if (attr_name == svg_names::kMinAttr) { - cached_min_ = kInvalidCachedTime; - } else if (attr_name == svg_names::kMaxAttr) { - cached_max_ = kInvalidCachedTime; - } else if (attr_name.Matches(svg_names::kHrefAttr) || - attr_name.Matches(xlink_names::kHrefAttr)) { + if (attr_name.Matches(svg_names::kHrefAttr) || + attr_name.Matches(xlink_names::kHrefAttr)) { // TODO(fs): Could be smarter here when 'href' is specified and 'xlink:href' // is changed. SVGElement::InvalidationGuard invalidation_guard(this); BuildPendingResource(); - } else { - SVGElement::SvgAttributeChanged(attr_name); return; } - - AnimationAttributeChanged(); + SVGElement::SvgAttributeChanged(attr_name); } void SVGSMILElement::ConnectConditions() {
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h index dbf83e6..6c85013 100644 --- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h +++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -56,7 +56,6 @@ void RemovedFrom(ContainerNode&) override; virtual bool HasValidTarget() const; - virtual void AnimationAttributeChanged() = 0; SMILTimeContainer* TimeContainer() const { return time_container_.Get(); } @@ -131,16 +130,12 @@ void AddInstanceTimeAndUpdate(BeginOrEnd, SMILTime, SMILTimeOrigin); - void SetInactive() { active_state_ = kInactive; } - void SetTargetElement(SVGElement*); // Sub-classes may need to take action when the target is changed. virtual void WillChangeAnimationTarget(); virtual void DidChangeAnimationTarget(); - virtual void StartedActiveInterval(); - QualifiedName attribute_name_; private: @@ -148,6 +143,7 @@ void ClearResourceAndEventBaseReferences(); void ClearConditions(); + void StartedActiveInterval(); void EndedActiveInterval(); virtual void UpdateAnimation(float percent, unsigned repeat,
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc index bad29363..e73be4a 100644 --- a/third_party/blink/renderer/core/svg/svg_animate_element.cc +++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -155,12 +155,10 @@ const AttributeModificationParams& params) { if (params.name == svg_names::kAttributeTypeAttr) { SetAttributeType(params.new_value); - AnimationAttributeChanged(); return; } if (params.name == svg_names::kAttributeNameAttr) { SetAttributeName(ConstructQualifiedName(*this, params.new_value)); - AnimationAttributeChanged(); return; } SVGAnimationElement::ParseAttribute(params); @@ -550,7 +548,9 @@ SVGAnimationElement::WillChangeAnimationTarget(); // Should be cleared by the above. DCHECK(!animated_value_); - ResetCachedAnimationState(); + from_property_.Clear(); + to_property_.Clear(); + to_at_end_of_duration_property_.Clear(); } void SVGAnimateElement::DidChangeAnimationTarget() { @@ -582,14 +582,6 @@ DidChangeAnimationTarget(); } -void SVGAnimateElement::ResetCachedAnimationState() { - DCHECK(!animated_value_); - InvalidatedValuesCache(); - from_property_.Clear(); - to_property_.Clear(); - to_at_end_of_duration_property_.Clear(); -} - void SVGAnimateElement::Trace(blink::Visitor* visitor) { visitor->Trace(from_property_); visitor->Trace(to_property_);
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.h b/third_party/blink/renderer/core/svg/svg_animate_element.h index 5bd334bb..91dad7aa 100644 --- a/third_party/blink/renderer/core/svg/svg_animate_element.h +++ b/third_party/blink/renderer/core/svg/svg_animate_element.h
@@ -90,8 +90,6 @@ stringsShouldNotSupportAddition); private: - void ResetCachedAnimationState(); - bool ShouldApplyAnimation(const SVGElement& target_element) const; void SetAttributeType(const AtomicString&);
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc index 0040d0a..86e0627b 100644 --- a/third_party/blink/renderer/core/svg/svg_animation_element.cc +++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -38,7 +38,7 @@ SVGAnimationElement::SVGAnimationElement(const QualifiedName& tag_name, Document& document) : SVGSMILElement(tag_name, document), - animation_valid_(false), + animation_valid_(AnimationValidity::kUnknown), calc_mode_(kCalcModeLinear), animation_mode_(kNoAnimation) { UseCounter::Count(document, WebFeature::kSVGAnimationElement); @@ -171,6 +171,7 @@ return; } UpdateAnimationMode(); + AnimationAttributeChanged(); return; } @@ -179,6 +180,7 @@ ReportAttributeParsingError(SVGParseStatus::kParsingFailed, name, params.new_value); } + AnimationAttributeChanged(); return; } @@ -191,6 +193,7 @@ params.new_value); } } + AnimationAttributeChanged(); return; } @@ -199,47 +202,36 @@ ReportAttributeParsingError(SVGParseStatus::kParsingFailed, name, params.new_value); } + AnimationAttributeChanged(); return; } if (name == svg_names::kCalcModeAttr) { SetCalcMode(params.new_value); + AnimationAttributeChanged(); return; } if (name == svg_names::kFromAttr || name == svg_names::kToAttr || name == svg_names::kByAttr) { UpdateAnimationMode(); + AnimationAttributeChanged(); return; } SVGSMILElement::ParseAttribute(params); } -void SVGAnimationElement::SvgAttributeChanged(const QualifiedName& attr_name) { - if (attr_name == svg_names::kValuesAttr || attr_name == svg_names::kByAttr || - attr_name == svg_names::kFromAttr || attr_name == svg_names::kToAttr || - attr_name == svg_names::kCalcModeAttr || - attr_name == svg_names::kKeySplinesAttr || - attr_name == svg_names::kKeyPointsAttr || - attr_name == svg_names::kKeyTimesAttr) { - AnimationAttributeChanged(); - return; - } - - SVGSMILElement::SvgAttributeChanged(attr_name); -} - -void SVGAnimationElement::InvalidatedValuesCache() { +void SVGAnimationElement::AnimationAttributeChanged() { + // Assumptions may not hold after an attribute change. + animation_valid_ = AnimationValidity::kUnknown; last_values_animation_from_ = String(); last_values_animation_to_ = String(); } -void SVGAnimationElement::AnimationAttributeChanged() { - // Assumptions may not hold after an attribute change. - animation_valid_ = false; - InvalidatedValuesCache(); - SetInactive(); +void SVGAnimationElement::WillChangeAnimationTarget() { + SVGSMILElement::WillChangeAnimationTarget(); + AnimationAttributeChanged(); } float SVGAnimationElement::getStartTime(ExceptionState& exception_state) const { @@ -472,7 +464,7 @@ String& from, String& to) { unsigned values_count = values_.size(); - DCHECK(animation_valid_); + DCHECK_EQ(animation_valid_, AnimationValidity::kValid); DCHECK_GE(values_count, 1u); if (percent == 1 || values_count == 1) { @@ -528,18 +520,14 @@ } } -void SVGAnimationElement::StartedActiveInterval() { - SVGSMILElement::StartedActiveInterval(); - - animation_valid_ = false; - +bool SVGAnimationElement::CheckAnimationParameters() { if (!IsValid() || !HasValidTarget()) - return; + return false; // These validations are appropriate for all animation modes. if (FastHasAttribute(svg_names::kKeyPointsAttr) && key_points_.size() != KeyTimes().size()) - return; + return false; AnimationMode animation_mode = GetAnimationMode(); CalcMode calc_mode = GetCalcMode(); @@ -552,34 +540,36 @@ values_.size() - 1 != splines_count) || (FastHasAttribute(svg_names::kKeyTimesAttr) && KeyTimes().size() - 1 != splines_count)) - return; + return false; } String from = FromValue(); String to = ToValue(); String by = ByValue(); if (animation_mode == kNoAnimation) - return; + return false; if ((animation_mode == kFromToAnimation || animation_mode == kFromByAnimation || animation_mode == kToAnimation || animation_mode == kByAnimation) && (FastHasAttribute(svg_names::kKeyPointsAttr) && FastHasAttribute(svg_names::kKeyTimesAttr) && (KeyTimes().size() < 2 || KeyTimes().size() != key_points_.size()))) - return; - if (animation_mode == kFromToAnimation) { - animation_valid_ = CalculateFromAndToValues(from, to); - } else if (animation_mode == kToAnimation) { + return false; + if (animation_mode == kFromToAnimation) + return CalculateFromAndToValues(from, to); + if (animation_mode == kToAnimation) { // For to-animations the from value is the current accumulated value from // lower priority animations. // The value is not static and is determined during the animation. - animation_valid_ = CalculateFromAndToValues(g_empty_string, to); - } else if (animation_mode == kFromByAnimation) { - animation_valid_ = CalculateFromAndByValues(from, by); - } else if (animation_mode == kByAnimation) { - animation_valid_ = CalculateFromAndByValues(g_empty_string, by); - } else if (animation_mode == kValuesAnimation) { - animation_valid_ = + return CalculateFromAndToValues(g_empty_string, to); + } + if (animation_mode == kFromByAnimation) + return CalculateFromAndByValues(from, by); + if (animation_mode == kByAnimation) + return CalculateFromAndByValues(g_empty_string, by); + if (animation_mode == kValuesAnimation) { + // o_O - TODO(fs): move this to a helper function. + bool animation_valid = values_.size() >= 1 && (calc_mode == kCalcModePaced || !FastHasAttribute(svg_names::kKeyTimesAttr) || @@ -593,25 +583,38 @@ key_splines_.size() == key_points_.size() - 1)) && (!FastHasAttribute(svg_names::kKeyPointsAttr) || (KeyTimes().size() > 1 && KeyTimes().size() == key_points_.size())); - if (animation_valid_) - animation_valid_ = CalculateToAtEndOfDurationValue(values_.back()); - if (calc_mode == kCalcModePaced && animation_valid_) + if (animation_valid) + animation_valid = CalculateToAtEndOfDurationValue(values_.back()); + if (calc_mode == kCalcModePaced && animation_valid) CalculateKeyTimesForCalcModePaced(); - } else if (animation_mode == kPathAnimation) { - animation_valid_ = - calc_mode == kCalcModePaced || - !FastHasAttribute(svg_names::kKeyPointsAttr) || - (KeyTimes().size() > 1 && KeyTimes().size() == key_points_.size()); + return animation_valid; } - - if (animation_valid_ && (IsAdditive() || IsAccumulated())) - UseCounter::Count(&GetDocument(), WebFeature::kSVGSMILAdditiveAnimation); + if (animation_mode == kPathAnimation) { + return calc_mode == kCalcModePaced || + !FastHasAttribute(svg_names::kKeyPointsAttr) || + (KeyTimes().size() > 1 && KeyTimes().size() == key_points_.size()); + } + return false; } void SVGAnimationElement::UpdateAnimation(float percent, unsigned repeat_count, SVGSMILElement* result_element) { - if (!animation_valid_ || !targetElement()) + if (animation_valid_ == AnimationValidity::kUnknown) { + if (CheckAnimationParameters()) { + animation_valid_ = AnimationValidity::kValid; + + if (IsAdditive() || IsAccumulated()) { + UseCounter::Count(&GetDocument(), + WebFeature::kSVGSMILAdditiveAnimation); + } + } else { + animation_valid_ = AnimationValidity::kInvalid; + } + } + DCHECK_NE(animation_valid_, AnimationValidity::kUnknown); + + if (animation_valid_ != AnimationValidity::kValid || !targetElement()) return; float effective_percent; @@ -623,9 +626,10 @@ CurrentValuesForValuesAnimation(percent, effective_percent, from, to); if (from != last_values_animation_from_ || to != last_values_animation_to_) { - animation_valid_ = CalculateFromAndToValues(from, to); - if (!animation_valid_) + if (!CalculateFromAndToValues(from, to)) { + animation_valid_ = AnimationValidity::kInvalid; return; + } last_values_animation_from_ = from; last_values_animation_to_ = to; }
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.h b/third_party/blink/renderer/core/svg/svg_animation_element.h index 92721a9..a434086fa 100644 --- a/third_party/blink/renderer/core/svg/svg_animation_element.h +++ b/third_party/blink/renderer/core/svg/svg_animation_element.h
@@ -114,14 +114,12 @@ SVGAnimationElement(const QualifiedName&, Document&); void ParseAttribute(const AttributeModificationParams&) override; - void SvgAttributeChanged(const QualifiedName&) override; String ToValue() const; String ByValue() const; String FromValue() const; // from SVGSMILElement - void StartedActiveInterval() override; void UpdateAnimation(float percent, unsigned repeat, SVGSMILElement* result_element) override; @@ -142,12 +140,13 @@ // http://www.w3.org/TR/SVG/animate.html#ValuesAttribute . static bool ParseValues(const String&, Vector<String>& result); - void InvalidatedValuesCache(); - void AnimationAttributeChanged() override; + void WillChangeAnimationTarget() override; private: bool IsValid() const final { return SVGTests::IsValid(); } + void AnimationAttributeChanged(); + bool CheckAnimationParameters(); virtual bool CalculateToAtEndOfDurationValue( const String& to_at_end_of_duration_string) = 0; virtual bool CalculateFromAndToValues(const String& from_string, @@ -186,7 +185,12 @@ void SetCalcMode(const AtomicString&); - bool animation_valid_; + enum class AnimationValidity : unsigned char { + kUnknown, + kValid, + kInvalid, + }; + AnimationValidity animation_valid_; bool use_paced_key_times_; Vector<String> values_;
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.h b/third_party/blink/renderer/core/svg/svg_discard_element.h index dffcf52..374a308 100644 --- a/third_party/blink/renderer/core/svg/svg_discard_element.h +++ b/third_party/blink/renderer/core/svg/svg_discard_element.h
@@ -47,7 +47,6 @@ void ResetAnimatedType() override {} void ClearAnimatedType() override {} void ApplyResultsToTarget() override {} - void AnimationAttributeChanged() override {} bool OverwritesUnderlyingAnimationValue() const override { return false; }
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js index d87913f..1ab288d5 100644 --- a/third_party/blink/renderer/devtools/front_end/main/Main.js +++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -136,7 +136,6 @@ 'recordCoverageWithPerformanceTracing', 'Record coverage while performance tracing'); Root.Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true); Root.Runtime.experiments.register('sourceDiff', 'Source diff'); - Root.Runtime.experiments.register('splitInDrawer', 'Split in drawer', true); Root.Runtime.experiments.register('spotlight', 'Spotlight', true); // Timeline
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/EmulationModel.js b/third_party/blink/renderer/devtools/front_end/sdk/EmulationModel.js index 0c23e275..724abf2b 100644 --- a/third_party/blink/renderer/devtools/front_end/sdk/EmulationModel.js +++ b/third_party/blink/renderer/devtools/front_end/sdk/EmulationModel.js
@@ -279,7 +279,8 @@ // but instead tries to make sense of the input, even for // weird-looking timezone IDs. There's not much point in validating // the input other than checking if it contains at least one slash. - const valid = value.includes('/'); + // The empty string resets the override, and is accepted as well. + const valid = value === '' || value.includes('/'); return {valid}; }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js b/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js index 25e37d5..bd395ae 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js +++ b/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js
@@ -44,16 +44,6 @@ this._drawerSplitWidget.enableShowModeSaving(); this._drawerSplitWidget.show(this.element); - if (Root.Runtime.experiments.isEnabled('splitInDrawer')) { - this._innerDrawerSplitWidget = new UI.SplitWidget(true, true, 'Inspector.drawerSidebarSplitViewState', 200, 200); - this._drawerSplitWidget.setSidebarWidget(this._innerDrawerSplitWidget); - this._drawerSidebarTabbedLocation = - UI.viewManager.createTabbedLocation(this._showDrawer.bind(this, false), 'drawer-sidebar', true, true); - this._drawerSidebarTabbedPane = this._drawerSidebarTabbedLocation.tabbedPane(); - this._drawerSidebarTabbedPane.addEventListener(UI.TabbedPane.Events.TabSelected, this._drawerTabSelected, this); - this._innerDrawerSplitWidget.setSidebarWidget(this._drawerSidebarTabbedPane); - } - // Create drawer tabbed pane. this._drawerTabbedLocation = UI.viewManager.createTabbedLocation(this._showDrawer.bind(this, false), 'drawer-view', true, true); @@ -66,14 +56,8 @@ this._drawerSplitWidget.installResizer(this._drawerTabbedPane.headerElement()); this._drawerTabbedPane.addEventListener(UI.TabbedPane.Events.TabSelected, this._drawerTabSelected, this); - if (this._drawerSidebarTabbedPane) { - this._innerDrawerSplitWidget.setMainWidget(this._drawerTabbedPane); - this._drawerSidebarTabbedPane.rightToolbar().appendToolbarItem(closeDrawerButton); - this._drawerSplitWidget.installResizer(this._drawerSidebarTabbedPane.headerElement()); - } else { - this._drawerSplitWidget.setSidebarWidget(this._drawerTabbedPane); - this._drawerTabbedPane.rightToolbar().appendToolbarItem(closeDrawerButton); - } + this._drawerSplitWidget.setSidebarWidget(this._drawerTabbedPane); + this._drawerTabbedPane.rightToolbar().appendToolbarItem(closeDrawerButton); // Create main area tabbed pane. this._tabbedLocation = UI.viewManager.createTabbedLocation( @@ -140,9 +124,6 @@ if (locationName === 'panel') { return this._tabbedLocation; } - if (locationName === 'drawer-sidebar') { - return this._drawerSidebarTabbedLocation; - } return null; }
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index cb8e5c0..5f787b71 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -150,6 +150,7 @@ "//third_party/blink/renderer/modules/webmidi", "//third_party/blink/renderer/modules/webshare", "//third_party/blink/renderer/modules/websockets", + "//third_party/blink/renderer/modules/webtransport", "//third_party/blink/renderer/modules/webusb", "//third_party/blink/renderer/modules/worklet", "//third_party/blink/renderer/modules/xr", @@ -401,8 +402,8 @@ "service_worker/service_worker_timeout_timer_test.cc", "service_worker/thread_safe_script_container_test.cc", "service_worker/web_embedded_worker_impl_test.cc", + "wake_lock/wake_lock_manager_test.cc", "wake_lock/wake_lock_sentinel_test.cc", - "wake_lock/wake_lock_state_record_test.cc", "wake_lock/wake_lock_test.cc", "wake_lock/wake_lock_test_utils.cc", "wake_lock/wake_lock_test_utils.h", @@ -458,6 +459,7 @@ "//third_party/blink/renderer/modules/gamepad:unit_tests", "//third_party/blink/renderer/modules/hid:unit_tests", "//third_party/blink/renderer/modules/storage:unit_tests", + "//third_party/blink/renderer/modules/webtransport:unit_tests", "//third_party/blink/renderer/platform", "//third_party/blink/renderer/platform/wtf", "//third_party/opus",
diff --git a/third_party/blink/renderer/modules/mediastream/DEPS b/third_party/blink/renderer/modules/mediastream/DEPS index 59774da..03a43394 100644 --- a/third_party/blink/renderer/modules/mediastream/DEPS +++ b/third_party/blink/renderer/modules/mediastream/DEPS
@@ -45,6 +45,7 @@ "+third_party/blink/renderer/modules/imagecapture", "+third_party/blink/renderer/modules/mediastream", "+third_party/blink/renderer/modules/modules_export.h", + "+third_party/blink/renderer/modules/peerconnection", "+ui/gfx/geometry/size.h", ]
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc index 3bf00e9..457f0f8 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
@@ -154,12 +154,14 @@ const base::Optional<int>& requested_buffer_size, bool disable_local_echo, bool enable_automatic_output_device_selection, + ProcessingType processing_type, const AudioProcessingProperties& audio_processing_properties) : failed_constraint_name_(nullptr), device_id_(std::move(device_id)), requested_buffer_size_(requested_buffer_size), disable_local_echo_(disable_local_echo), render_to_associated_sink_(enable_automatic_output_device_selection), + processing_type_(processing_type), audio_processing_properties_(audio_processing_properties) {} AudioCaptureSettings::AudioCaptureSettings(const AudioCaptureSettings& other) =
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc index 1a2a3bd..7b1c579a 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
@@ -795,6 +795,8 @@ sample_rate_container_.IsEmpty() || latency_container_.IsEmpty(); } + ProcessingType processing_type() const { return processing_type_; } + private: enum BooleanContainerId { kGoogAudioMirroring, @@ -996,41 +998,27 @@ // Three variations of the processing-based container. Each variant is // associated to a different type of audio processing configuration, namely // unprocessed, processed by WebRTC, or processed by other means. - if (is_reconfiguration_allowed || source_info.type() == SourceType::kNone || - source_info.type() == SourceType::kUnprocessed) { + processing_based_containers_.push_back( + ProcessingBasedContainer::CreateUnprocessedContainer( + source_info, is_device_capture, device_parameters_, + is_reconfiguration_allowed)); + processing_based_containers_.push_back( + ProcessingBasedContainer::CreateNoApmProcessedContainer( + source_info, is_device_capture, device_parameters_, + is_reconfiguration_allowed)); + if (media::IsWebRtcApmInAudioServiceEnabled()) { processing_based_containers_.push_back( - ProcessingBasedContainer::CreateUnprocessedContainer( + ProcessingBasedContainer::CreateRemoteApmProcessedContainer( source_info, is_device_capture, device_parameters_, is_reconfiguration_allowed)); - } - if (is_reconfiguration_allowed || source_info.type() == SourceType::kNone || - source_info.type() == SourceType::kNoApmProcessed) { + } else { processing_based_containers_.push_back( - ProcessingBasedContainer::CreateNoApmProcessedContainer( + ProcessingBasedContainer::CreateApmProcessedContainer( source_info, is_device_capture, device_parameters_, is_reconfiguration_allowed)); } - if (is_reconfiguration_allowed || source_info.type() == SourceType::kNone || - source_info.type() == SourceType::kApmProcessed) { - if (media::IsWebRtcApmInAudioServiceEnabled()) { - processing_based_containers_.push_back( - ProcessingBasedContainer::CreateRemoteApmProcessedContainer( - source_info, is_device_capture, device_parameters_, - is_reconfiguration_allowed)); - } else { - processing_based_containers_.push_back( - ProcessingBasedContainer::CreateApmProcessedContainer( - source_info, is_device_capture, device_parameters_, - is_reconfiguration_allowed)); - } - } -#if DCHECK_IS_ON() - if (is_reconfiguration_allowed || source_info.type() == SourceType::kNone) - DCHECK_EQ(processing_based_containers_.size(), 3u); - else - DCHECK_EQ(processing_based_containers_.size(), 1u); -#endif + DCHECK_EQ(processing_based_containers_.size(), 3u); if (source_info.type() == SourceType::kNone) return; @@ -1164,7 +1152,8 @@ return std::make_tuple( score, AudioCaptureSettings( device_id, best_requested_buffer_size, disable_local_echo, - render_to_associated_sink, best_properties)); + render_to_associated_sink, best_container->processing_type(), + best_properties)); } // The DeviceContainer is considered empty if at least one of the
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc index e062b237..72327ac 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
@@ -33,6 +33,7 @@ using blink::AudioCaptureSettings; using blink::AudioProcessingProperties; using EchoCancellationType = AudioProcessingProperties::EchoCancellationType; +using ProcessingType = AudioCaptureSettings::ProcessingType; namespace { @@ -60,6 +61,15 @@ using AudioPropertiesBoolMembers = std::vector<bool AudioProcessingProperties::*>; +const AudioPropertiesBoolMembers kAudioProcessingProperties = { + &AudioProcessingProperties::goog_audio_mirroring, + &AudioProcessingProperties::goog_auto_gain_control, + &AudioProcessingProperties::goog_experimental_echo_cancellation, + &AudioProcessingProperties::goog_noise_suppression, + &AudioProcessingProperties::goog_experimental_noise_suppression, + &AudioProcessingProperties::goog_highpass_filter, + &AudioProcessingProperties::goog_experimental_auto_gain_control}; + template <typename T> static bool Contains(const std::vector<T>& vector, T value) { return base::Contains(vector, value); @@ -303,6 +313,31 @@ } } + void CheckProcessingType(const AudioCaptureSettings& result) { + ProcessingType expected_type = ProcessingType::kUnprocessed; + const auto& properties = result.audio_processing_properties(); + bool properties_value = false; + // Skip audio mirroring and start directly from auto gain control. + for (size_t i = 1; i < kAudioProcessingProperties.size(); ++i) + properties_value |= properties.*kAudioProcessingProperties[i]; + + // If goog_audio_mirroring is true but all the other properties are false, + // we should be expecting kProcessed, however if any of the properties was + // true, we should expected kApmProcessed. + if (properties.goog_audio_mirroring && !properties_value) + expected_type = ProcessingType::kNoApmProcessed; + else if (properties_value) + expected_type = ProcessingType::kApmProcessed; + + // Finally, if the chosen echo cancellation type is either AEC3 or AEC2, the + // only possible processing type to expect is kWebRtcProcessed. + if (properties.echo_cancellation_type == + EchoCancellationType::kEchoCancellationAec3) { + expected_type = ProcessingType::kApmProcessed; + } + EXPECT_EQ(result.processing_type(), expected_type); + } + void CheckDevice(const AudioDeviceCaptureCapability& expected_device, const AudioCaptureSettings& result) { EXPECT_EQ(expected_device.DeviceID().Utf8(), result.device_id()); @@ -319,6 +354,7 @@ const AudioSettingsBoolMembers& exclude_main_settings, const AudioPropertiesBoolMembers& exclude_audio_properties, const AudioCaptureSettings& result) { + CheckProcessingType(result); CheckBoolDefaults(exclude_main_settings, exclude_audio_properties, result); CheckEchoCancellationTypeDefault(result); CheckDeviceDefaults(result); @@ -576,15 +612,6 @@ } } - const AudioPropertiesBoolMembers kAudioProcessingProperties = { - &AudioProcessingProperties::goog_audio_mirroring, - &AudioProcessingProperties::goog_auto_gain_control, - &AudioProcessingProperties::goog_experimental_echo_cancellation, - &AudioProcessingProperties::goog_noise_suppression, - &AudioProcessingProperties::goog_experimental_noise_suppression, - &AudioProcessingProperties::goog_highpass_filter, - &AudioProcessingProperties::goog_experimental_auto_gain_control}; - const std::vector< blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*> kAudioProcessingConstraints = { @@ -1161,6 +1188,7 @@ CheckDeviceDefaults(result); else EXPECT_EQ(kArbitraryDeviceID, result.device_id()); + CheckProcessingType(result); CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), result); CheckEchoCancellationTypeDefault(result); @@ -1173,6 +1201,7 @@ auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); CheckDevice(device, result); + CheckProcessingType(result); CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), result); EchoCancellationType expected_echo_cancellation_type = @@ -1198,6 +1227,7 @@ auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); CheckDevice(device, result); + CheckProcessingType(result); CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), result); EchoCancellationType expected_echo_cancellation_type = @@ -1266,6 +1296,7 @@ EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop, result.disable_local_echo()); EXPECT_FALSE(result.render_to_associated_sink()); + CheckProcessingType(result); if (IsDeviceCapture()) { CheckDevice(*default_device_, result); } else { @@ -1324,6 +1355,7 @@ EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop, result.disable_local_echo()); EXPECT_FALSE(result.render_to_associated_sink()); + CheckProcessingType(result); CheckDevice(*system_echo_canceller_device_, result); } } @@ -1358,6 +1390,7 @@ : EchoCancellationType::kEchoCancellationDisabled; EXPECT_EQ(expected_echo_cancellation_type, properties.echo_cancellation_type); + CheckProcessingType(result); CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), result); if (IsDeviceCapture()) { @@ -1405,6 +1438,7 @@ : EchoCancellationType::kEchoCancellationDisabled; EXPECT_EQ(expected_echo_cancellation_type, properties.echo_cancellation_type); + CheckProcessingType(result); CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), result); CheckDevice(*system_echo_canceller_device_, result); @@ -1430,14 +1464,6 @@ // default value set by the echoCancellation constraint. TEST_P(MediaStreamConstraintsUtilAudioTest, EchoCancellationAndSingleBoolConstraint) { - const AudioPropertiesBoolMembers kAudioProcessingProperties = { - &AudioProcessingProperties::goog_audio_mirroring, - &AudioProcessingProperties::goog_auto_gain_control, - &AudioProcessingProperties::goog_experimental_echo_cancellation, - &AudioProcessingProperties::goog_noise_suppression, - &AudioProcessingProperties::goog_experimental_noise_suppression, - &AudioProcessingProperties::goog_highpass_filter, - &AudioProcessingProperties::goog_experimental_auto_gain_control}; const std::vector< blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*> @@ -1473,6 +1499,7 @@ set_function)(true); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); + CheckProcessingType(result); EXPECT_EQ(EchoCancellationType::kEchoCancellationDisabled, result.audio_processing_properties().echo_cancellation_type); EXPECT_TRUE(result.audio_processing_properties().* @@ -1531,6 +1558,7 @@ auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); CheckDeviceDefaults(result); + CheckProcessingType(result); CheckBoolDefaults({&AudioCaptureSettings::render_to_associated_sink}, {&AudioProcessingProperties::goog_audio_mirroring}, result); CheckEchoCancellationTypeDefault(result); @@ -1549,6 +1577,7 @@ constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); + CheckProcessingType(result); CheckDeviceDefaults(result); CheckBoolDefaults({}, {&AudioProcessingProperties::goog_audio_mirroring, @@ -1566,6 +1595,7 @@ constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); + CheckProcessingType(result); CheckDeviceDefaults(result); CheckBoolDefaults({}, {&AudioProcessingProperties::goog_audio_mirroring, @@ -1695,15 +1725,6 @@ &blink::WebMediaTrackConstraintSet:: goog_experimental_auto_gain_control, }; - const AudioPropertiesBoolMembers kAudioProcessingProperties = { - &AudioProcessingProperties::goog_audio_mirroring, - &AudioProcessingProperties::goog_auto_gain_control, - &AudioProcessingProperties::goog_experimental_echo_cancellation, - &AudioProcessingProperties::goog_noise_suppression, - &AudioProcessingProperties::goog_experimental_noise_suppression, - &AudioProcessingProperties::goog_highpass_filter, - &AudioProcessingProperties::goog_experimental_auto_gain_control}; - ASSERT_EQ(kAudioProcessingConstraints.size(), kAudioProcessingProperties.size());
diff --git a/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc b/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc index fc133f77..9086130 100644 --- a/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc +++ b/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc
@@ -9,7 +9,7 @@ #include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h" #include "third_party/blink/public/platform/modules/webrtc/track_observer.h" #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h" -#include "third_party/blink/public/web/modules/peerconnection/media_stream_remote_video_source.h" +#include "third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" #include "third_party/blink/renderer/platform/webrtc/peer_connection_remote_audio_source.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 0cb0b74..b319564 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -497,6 +497,7 @@ "websockets/close_event.idl", "websockets/websocket.idl", "websockets/websocket_stream.idl", + "webtransport/quic_transport.idl", "webusb/usb.idl", "webusb/usb_alternate_interface.idl", "webusb/usb_configuration.idl",
diff --git a/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/third_party/blink/renderer/modules/peerconnection/BUILD.gn index 32ce674d..dd58e136 100644 --- a/third_party/blink/renderer/modules/peerconnection/BUILD.gn +++ b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -53,6 +53,7 @@ "call_setup_state_tracker.cc", "call_setup_state_tracker.h", "media_stream_remote_video_source.cc", + "media_stream_remote_video_source.h", "media_stream_video_webrtc_sink.cc", "peer_connection_dependency_factory.cc", "rtc_certificate.cc",
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc index 77da47c9..944a4751 100644 --- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc +++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/public/web/modules/peerconnection/media_stream_remote_video_source.h" +#include "third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h" #include <stdint.h> #include <utility>
diff --git a/third_party/blink/public/web/modules/peerconnection/media_stream_remote_video_source.h b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h similarity index 79% rename from third_party/blink/public/web/modules/peerconnection/media_stream_remote_video_source.h rename to third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h index a0ee73b..9f53584 100644 --- a/third_party/blink/public/web/modules/peerconnection/media_stream_remote_video_source.h +++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_PEERCONNECTION_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ -#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_PEERCONNECTION_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ #include <memory> #include "base/macros.h" -#include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_media_stream_source.h" #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h" +#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/webrtc/api/media_stream_interface.h" namespace blink { @@ -22,10 +22,7 @@ // class is to make sure there is no difference between a video track where the // source is a local source and a video track where the source is a remote video // track. -// -// TODO(crbug.com/787254): Move the classes below out of the Blink exposed -// API when all users of it have been Onion souped. -class BLINK_MODULES_EXPORT MediaStreamRemoteVideoSource +class MODULES_EXPORT MediaStreamRemoteVideoSource : public MediaStreamVideoSource { public: explicit MediaStreamRemoteVideoSource( @@ -62,4 +59,4 @@ } // namespace blink -#endif // THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_PEERCONNECTION_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc index 2e9aa9dd..1125ad8 100644 --- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/public/web/modules/peerconnection/media_stream_remote_video_source.h" +#include "third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h" #include <memory> #include <utility>
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc index 729d72c..53b6a7e 100644 --- a/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc +++ b/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc
@@ -14,11 +14,11 @@ #include "base/synchronization/lock.h" #include "base/timer/timer.h" #include "media/base/limits.h" -#include "third_party/blink/public/platform/modules/peerconnection/webrtc_video_track_source.h" #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h" #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h" #include "third_party/blink/public/web/modules/mediastream/web_media_stream_utils.h" #include "third_party/blink/public/web/modules/peerconnection/peer_connection_dependency_factory.h" +#include "third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/webrtc/api/video_track_source_proxy.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc index 65ff7e67..6155156 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
@@ -24,7 +24,6 @@ #include "media/video/gpu_video_accelerator_factories.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h" -#include "third_party/blink/public/platform/modules/peerconnection/audio_codec_factory.h" #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_media_constraints.h" @@ -45,6 +44,7 @@ #include "third_party/blink/renderer/platform/p2p/ipc_socket_factory.h" #include "third_party/blink/renderer/platform/p2p/mdns_responder_adapter.h" #include "third_party/blink/renderer/platform/p2p/socket_dispatcher.h" +#include "third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h" #include "third_party/blink/renderer/platform/peerconnection/stun_field_trial.h" #include "third_party/blink/renderer/platform/peerconnection/video_codec_factory.h" #include "third_party/webrtc/api/call/call_factory_interface.h"
diff --git a/third_party/blink/renderer/modules/wake_lock/BUILD.gn b/third_party/blink/renderer/modules/wake_lock/BUILD.gn index e77edec..1a36840 100644 --- a/third_party/blink/renderer/modules/wake_lock/BUILD.gn +++ b/third_party/blink/renderer/modules/wake_lock/BUILD.gn
@@ -10,10 +10,10 @@ "navigator_wake_lock.h", "wake_lock.cc", "wake_lock.h", + "wake_lock_manager.cc", + "wake_lock_manager.h", "wake_lock_sentinel.cc", "wake_lock_sentinel.h", - "wake_lock_state_record.cc", - "wake_lock_state_record.h", "wake_lock_type.cc", "wake_lock_type.h", "worker_navigator_wake_lock.cc",
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock.cc index 4d6da59..652e18b6 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
@@ -12,7 +12,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/modules/permissions/permission_utils.h" -#include "third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h" +#include "third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h" #include "third_party/blink/renderer/modules/wake_lock/wake_lock_type.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -26,20 +26,18 @@ WakeLock::WakeLock(Document& document) : ContextLifecycleObserver(&document), PageVisibilityObserver(document.GetPage()), - state_records_{ - MakeGarbageCollected<WakeLockStateRecord>(&document, - WakeLockType::kScreen), - MakeGarbageCollected<WakeLockStateRecord>(&document, - WakeLockType::kSystem)} {} + managers_{MakeGarbageCollected<WakeLockManager>(&document, + WakeLockType::kScreen), + MakeGarbageCollected<WakeLockManager>(&document, + WakeLockType::kSystem)} {} WakeLock::WakeLock(DedicatedWorkerGlobalScope& worker_scope) : ContextLifecycleObserver(&worker_scope), PageVisibilityObserver(nullptr), - state_records_{ - MakeGarbageCollected<WakeLockStateRecord>(&worker_scope, - WakeLockType::kScreen), - MakeGarbageCollected<WakeLockStateRecord>(&worker_scope, - WakeLockType::kSystem)} {} + managers_{MakeGarbageCollected<WakeLockManager>(&worker_scope, + WakeLockType::kScreen), + MakeGarbageCollected<WakeLockManager>(&worker_scope, + WakeLockType::kSystem)} {} ScriptPromise WakeLock::request(ScriptState* script_state, const String& type) { // https://w3c.github.io/wake-lock/#request-static-method @@ -161,7 +159,7 @@ return; } // https://github.com/w3c/wake-lock/issues/222: the page can become hidden - // between request() and WakeLockStateRecord::AcquireWakeLock(), in which case + // between request() and WakeLockManager::AcquireWakeLock(), in which case // we need to abort early. if (type == WakeLockType::kScreen && !(GetPage() && GetPage()->IsPageVisible())) { @@ -174,9 +172,9 @@ // and type: // 6.2.1. If success is false then reject promise with a "NotAllowedError" // DOMException, and abort these steps. - WakeLockStateRecord* state_record = state_records_[static_cast<size_t>(type)]; - DCHECK(state_record); - state_record->AcquireWakeLock(resolver); + WakeLockManager* manager = managers_[static_cast<size_t>(type)]; + DCHECK(manager); + manager->AcquireWakeLock(resolver); } void WakeLock::ContextDestroyed(ExecutionContext*) { @@ -184,15 +182,15 @@ // 1. Let document be the responsible document of the current settings object. // 2. Let screenRecord be the platform wake lock's state record associated // with document and wake lock type "screen". - // 3. For each lockPromise in screenRecord.[[WakeLockStateRecord]]: + // 3. For each lockPromise in screenRecord.[[ActiveLocks]]: // 3.1. Run release a wake lock with lockPromise and "screen". // 4. Let systemRecord be the platform wake lock's state record associated // with document and wake lock type "system". - // 5. For each lockPromise in systemRecord.[[WakeLockStateRecord]]: + // 5. For each lockPromise in systemRecord.[[ActiveLocks]]: // 5.1. Run release a wake lock with lockPromise and "system". - for (WakeLockStateRecord* state_record : state_records_) { - if (state_record) - state_record->ClearWakeLocks(); + for (WakeLockManager* manager : managers_) { + if (manager) + manager->ClearWakeLocks(); } } @@ -204,12 +202,12 @@ return; // 3. Let screenRecord be the platform wake lock's state record associated // with wake lock type "screen". - // 4. For each lockPromise in screenRecord.[[WakeLockStateRecord]]: + // 4. For each lockPromise in screenRecord.[[ActiveLocks]]: // 4.1. Run release a wake lock with lockPromise and "screen". - WakeLockStateRecord* state_record = - state_records_[static_cast<size_t>(WakeLockType::kScreen)]; - if (state_record) - state_record->ClearWakeLocks(); + WakeLockManager* manager = + managers_[static_cast<size_t>(WakeLockType::kScreen)]; + if (manager) + manager->ClearWakeLocks(); } void WakeLock::ObtainPermission( @@ -258,8 +256,8 @@ } void WakeLock::Trace(Visitor* visitor) { - for (WakeLockStateRecord* state_record : state_records_) - visitor->Trace(state_record); + for (WakeLockManager* manager : managers_) + visitor->Trace(manager); PageVisibilityObserver::Trace(visitor); ContextLifecycleObserver::Trace(visitor); ScriptWrappable::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock.h b/third_party/blink/renderer/modules/wake_lock/wake_lock.h index a22e5e2..42874c4 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock.h +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock.h
@@ -28,7 +28,7 @@ class ExecutionContext; class ScriptState; -class WakeLockStateRecord; +class WakeLockManager; class MODULES_EXPORT WakeLock final : public ScriptWrappable, public ContextLifecycleObserver, @@ -71,7 +71,7 @@ // https://w3c.github.io/wake-lock/#concepts-and-state-record // Each platform wake lock (one per wake lock type) has an associated state // record per responsible document [...] internal slots. - Member<WakeLockStateRecord> state_records_[kWakeLockTypeCount]; + Member<WakeLockManager> managers_[kWakeLockTypeCount]; FRIEND_TEST_ALL_PREFIXES(WakeLockTest, RequestWakeLockGranted); FRIEND_TEST_ALL_PREFIXES(WakeLockTest, RequestWakeLockDenied);
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc similarity index 80% rename from third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.cc rename to third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc index c5194fb2de..dade239 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h" +#include "third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h" #include "base/logging.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" @@ -15,13 +15,13 @@ namespace blink { -WakeLockStateRecord::WakeLockStateRecord(ExecutionContext* execution_context, - WakeLockType type) +WakeLockManager::WakeLockManager(ExecutionContext* execution_context, + WakeLockType type) : wake_lock_type_(type), execution_context_(execution_context) { DCHECK_NE(execution_context, nullptr); } -void WakeLockStateRecord::AcquireWakeLock(ScriptPromiseResolver* resolver) { +void WakeLockManager::AcquireWakeLock(ScriptPromiseResolver* resolver) { // https://w3c.github.io/wake-lock/#acquire-wake-lock-algorithm // 1. If the wake lock for type type is not applicable, return false. // 2. Set active to true if the platform wake lock has an active wake lock for @@ -34,7 +34,7 @@ // object. // 4.2. Let record be the platform wake lock's state record associated with // document and type. - // 4.3. Add lockPromise to record.[[WakeLockStateRecord]]. + // 4.3. Add lockPromise to record.[[ActiveLocks]]. // 5. Return active. if (!wake_lock_) { mojo::Remote<mojom::blink::WakeLockService> wake_lock_service; @@ -45,9 +45,8 @@ device::mojom::blink::WakeLockReason::kOther, "Blink Wake Lock", wake_lock_.BindNewPipeAndPassReceiver()); - wake_lock_.set_disconnect_handler( - WTF::Bind(&WakeLockStateRecord::OnWakeLockConnectionError, - WrapWeakPersistent(this))); + wake_lock_.set_disconnect_handler(WTF::Bind( + &WakeLockManager::OnWakeLockConnectionError, WrapWeakPersistent(this))); wake_lock_->RequestWakeLock(); } auto* sentinel = MakeGarbageCollected<WakeLockSentinel>( @@ -56,7 +55,7 @@ resolver->Resolve(sentinel); } -void WakeLockStateRecord::UnregisterSentinel(WakeLockSentinel* sentinel) { +void WakeLockManager::UnregisterSentinel(WakeLockSentinel* sentinel) { auto iterator = wake_lock_sentinels_.find(sentinel); DCHECK(iterator != wake_lock_sentinels_.end()); wake_lock_sentinels_.erase(iterator); @@ -67,17 +66,17 @@ } } -void WakeLockStateRecord::ClearWakeLocks() { +void WakeLockManager::ClearWakeLocks() { while (!wake_lock_sentinels_.IsEmpty()) (*wake_lock_sentinels_.begin())->DoRelease(); } -void WakeLockStateRecord::OnWakeLockConnectionError() { +void WakeLockManager::OnWakeLockConnectionError() { wake_lock_.reset(); ClearWakeLocks(); } -void WakeLockStateRecord::Trace(blink::Visitor* visitor) { +void WakeLockManager::Trace(blink::Visitor* visitor) { visitor->Trace(execution_context_); visitor->Trace(wake_lock_sentinels_); }
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h b/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h similarity index 69% rename from third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h rename to third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h index c40a504..32efa02 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WAKE_LOCK_STATE_RECORD_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WAKE_LOCK_STATE_RECORD_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WAKE_LOCK_MANAGER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WAKE_LOCK_MANAGER_H_ #include "base/gtest_prod_util.h" #include "mojo/public/cpp/bindings/remote.h" @@ -20,10 +20,10 @@ // https://w3c.github.io/wake-lock/#concepts-and-state-record // Per-document and per-wake lock type internal data. -class MODULES_EXPORT WakeLockStateRecord final - : public GarbageCollected<WakeLockStateRecord> { +class MODULES_EXPORT WakeLockManager final + : public GarbageCollected<WakeLockManager> { public: - WakeLockStateRecord(ExecutionContext*, WakeLockType); + WakeLockManager(ExecutionContext*, WakeLockType); void AcquireWakeLock(ScriptPromiseResolver*); void ClearWakeLocks(); @@ -48,13 +48,13 @@ // ExecutionContext from which we will connect to |wake_lock_service_|. Member<ExecutionContext> execution_context_; - FRIEND_TEST_ALL_PREFIXES(WakeLockStateRecordTest, AcquireWakeLock); - FRIEND_TEST_ALL_PREFIXES(WakeLockStateRecordTest, ReleaseAllWakeLocks); - FRIEND_TEST_ALL_PREFIXES(WakeLockStateRecordTest, ReleaseOneWakeLock); - FRIEND_TEST_ALL_PREFIXES(WakeLockStateRecordTest, ClearWakeLocks); - FRIEND_TEST_ALL_PREFIXES(WakeLockStateRecordTest, WakeLockConnectionError); + FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, AcquireWakeLock); + FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, ReleaseAllWakeLocks); + FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, ReleaseOneWakeLock); + FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, ClearWakeLocks); + FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, WakeLockConnectionError); }; } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WAKE_LOCK_STATE_RECORD_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WAKE_LOCK_MANAGER_H_
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record_test.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_manager_test.cc similarity index 65% rename from third_party/blink/renderer/modules/wake_lock/wake_lock_state_record_test.cc rename to third_party/blink/renderer/modules/wake_lock/wake_lock_manager_test.cc index ed2828c..d3ebd99 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record_test.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_manager_test.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h" +#include "third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" @@ -18,22 +18,22 @@ namespace { -WakeLockStateRecord* MakeStateRecord(WakeLockTestingContext& context, - WakeLockType type) { - return MakeGarbageCollected<WakeLockStateRecord>(context.GetDocument(), type); +WakeLockManager* MakeManager(WakeLockTestingContext& context, + WakeLockType type) { + return MakeGarbageCollected<WakeLockManager>(context.GetDocument(), type); } } // namespace -TEST(WakeLockStateRecordTest, AcquireWakeLock) { +TEST(WakeLockManagerTest, AcquireWakeLock) { MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeStateRecord(context, WakeLockType::kScreen); + auto* manager = MakeManager(context, WakeLockType::kScreen); MockWakeLock& screen_lock = wake_lock_service.get_wake_lock(WakeLockType::kScreen); EXPECT_FALSE(screen_lock.is_acquired()); - EXPECT_FALSE(state_record->wake_lock_.is_bound()); + EXPECT_FALSE(manager->wake_lock_.is_bound()); auto* resolver1 = MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); @@ -42,8 +42,8 @@ MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); ScriptPromise promise2 = resolver2->Promise(); - state_record->AcquireWakeLock(resolver1); - state_record->AcquireWakeLock(resolver2); + manager->AcquireWakeLock(resolver1); + manager->AcquireWakeLock(resolver2); screen_lock.WaitForRequest(); context.WaitForPromiseFulfillment(promise1); @@ -54,17 +54,17 @@ auto* sentinel2 = ScriptPromiseUtils::GetPromiseResolutionAsWakeLockSentinel(promise2); - EXPECT_TRUE(state_record->wake_lock_sentinels_.Contains(sentinel1)); - EXPECT_TRUE(state_record->wake_lock_sentinels_.Contains(sentinel2)); - EXPECT_EQ(2U, state_record->wake_lock_sentinels_.size()); + EXPECT_TRUE(manager->wake_lock_sentinels_.Contains(sentinel1)); + EXPECT_TRUE(manager->wake_lock_sentinels_.Contains(sentinel2)); + EXPECT_EQ(2U, manager->wake_lock_sentinels_.size()); EXPECT_TRUE(screen_lock.is_acquired()); - EXPECT_TRUE(state_record->wake_lock_.is_bound()); + EXPECT_TRUE(manager->wake_lock_.is_bound()); } -TEST(WakeLockStateRecordTest, ReleaseAllWakeLocks) { +TEST(WakeLockManagerTest, ReleaseAllWakeLocks) { MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeStateRecord(context, WakeLockType::kScreen); + auto* manager = MakeManager(context, WakeLockType::kScreen); MockWakeLock& screen_lock = wake_lock_service.get_wake_lock(WakeLockType::kScreen); @@ -73,28 +73,28 @@ MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); ScriptPromise promise = resolver->Promise(); - state_record->AcquireWakeLock(resolver); + manager->AcquireWakeLock(resolver); screen_lock.WaitForRequest(); context.WaitForPromiseFulfillment(promise); - EXPECT_EQ(1U, state_record->wake_lock_sentinels_.size()); + EXPECT_EQ(1U, manager->wake_lock_sentinels_.size()); EXPECT_TRUE(screen_lock.is_acquired()); auto* sentinel = ScriptPromiseUtils::GetPromiseResolutionAsWakeLockSentinel(promise); - state_record->UnregisterSentinel(sentinel); + manager->UnregisterSentinel(sentinel); screen_lock.WaitForCancelation(); - EXPECT_EQ(0U, state_record->wake_lock_sentinels_.size()); + EXPECT_EQ(0U, manager->wake_lock_sentinels_.size()); EXPECT_FALSE(screen_lock.is_acquired()); - EXPECT_FALSE(state_record->wake_lock_.is_bound()); + EXPECT_FALSE(manager->wake_lock_.is_bound()); } -TEST(WakeLockStateRecordTest, ReleaseOneWakeLock) { +TEST(WakeLockManagerTest, ReleaseOneWakeLock) { MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeStateRecord(context, WakeLockType::kScreen); + auto* manager = MakeManager(context, WakeLockType::kScreen); MockWakeLock& screen_lock = wake_lock_service.get_wake_lock(WakeLockType::kScreen); @@ -106,46 +106,46 @@ MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); ScriptPromise promise2 = resolver2->Promise(); - state_record->AcquireWakeLock(resolver1); - state_record->AcquireWakeLock(resolver2); + manager->AcquireWakeLock(resolver1); + manager->AcquireWakeLock(resolver2); screen_lock.WaitForRequest(); context.WaitForPromiseFulfillment(promise1); context.WaitForPromiseFulfillment(promise2); EXPECT_TRUE(screen_lock.is_acquired()); - EXPECT_EQ(2U, state_record->wake_lock_sentinels_.size()); + EXPECT_EQ(2U, manager->wake_lock_sentinels_.size()); auto* sentinel1 = ScriptPromiseUtils::GetPromiseResolutionAsWakeLockSentinel(promise1); - EXPECT_TRUE(state_record->wake_lock_sentinels_.Contains(sentinel1)); + EXPECT_TRUE(manager->wake_lock_sentinels_.Contains(sentinel1)); - state_record->UnregisterSentinel(sentinel1); - EXPECT_FALSE(state_record->wake_lock_sentinels_.Contains(sentinel1)); - EXPECT_TRUE(state_record->wake_lock_.is_bound()); - EXPECT_EQ(1U, state_record->wake_lock_sentinels_.size()); + manager->UnregisterSentinel(sentinel1); + EXPECT_FALSE(manager->wake_lock_sentinels_.Contains(sentinel1)); + EXPECT_TRUE(manager->wake_lock_.is_bound()); + EXPECT_EQ(1U, manager->wake_lock_sentinels_.size()); EXPECT_TRUE(screen_lock.is_acquired()); } -TEST(WakeLockStateRecordTest, ClearEmptyWakeLockSentinelList) { +TEST(WakeLockManagerTest, ClearEmptyWakeLockSentinelList) { MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeStateRecord(context, WakeLockType::kSystem); + auto* manager = MakeManager(context, WakeLockType::kSystem); MockWakeLock& system_lock = wake_lock_service.get_wake_lock(WakeLockType::kSystem); EXPECT_FALSE(system_lock.is_acquired()); - state_record->ClearWakeLocks(); + manager->ClearWakeLocks(); test::RunPendingTasks(); EXPECT_FALSE(system_lock.is_acquired()); } -TEST(WakeLockStateRecordTest, ClearWakeLocks) { +TEST(WakeLockManagerTest, ClearWakeLocks) { MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeStateRecord(context, WakeLockType::kSystem); + auto* manager = MakeManager(context, WakeLockType::kSystem); auto* resolver1 = MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); @@ -157,25 +157,25 @@ MockWakeLock& system_lock = wake_lock_service.get_wake_lock(WakeLockType::kSystem); - state_record->AcquireWakeLock(resolver1); - state_record->AcquireWakeLock(resolver2); + manager->AcquireWakeLock(resolver1); + manager->AcquireWakeLock(resolver2); system_lock.WaitForRequest(); context.WaitForPromiseFulfillment(promise1); context.WaitForPromiseFulfillment(promise2); - EXPECT_EQ(2U, state_record->wake_lock_sentinels_.size()); + EXPECT_EQ(2U, manager->wake_lock_sentinels_.size()); - state_record->ClearWakeLocks(); + manager->ClearWakeLocks(); system_lock.WaitForCancelation(); - EXPECT_EQ(0U, state_record->wake_lock_sentinels_.size()); + EXPECT_EQ(0U, manager->wake_lock_sentinels_.size()); EXPECT_FALSE(system_lock.is_acquired()); } -TEST(WakeLockStateRecordTest, WakeLockConnectionError) { +TEST(WakeLockManagerTest, WakeLockConnectionError) { MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeStateRecord(context, WakeLockType::kSystem); + auto* manager = MakeManager(context, WakeLockType::kSystem); auto* resolver1 = MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); @@ -187,21 +187,21 @@ MockWakeLock& system_lock = wake_lock_service.get_wake_lock(WakeLockType::kSystem); - state_record->AcquireWakeLock(resolver1); - state_record->AcquireWakeLock(resolver2); + manager->AcquireWakeLock(resolver1); + manager->AcquireWakeLock(resolver2); system_lock.WaitForRequest(); context.WaitForPromiseFulfillment(promise1); context.WaitForPromiseFulfillment(promise2); - EXPECT_EQ(2U, state_record->wake_lock_sentinels_.size()); + EXPECT_EQ(2U, manager->wake_lock_sentinels_.size()); // Unbind and wait for the disconnection to reach |wake_lock_|'s // disconnection handler. system_lock.Unbind(); - state_record->wake_lock_.FlushForTesting(); + manager->wake_lock_.FlushForTesting(); - EXPECT_EQ(0U, state_record->wake_lock_sentinels_.size()); - EXPECT_FALSE(state_record->wake_lock_); + EXPECT_EQ(0U, manager->wake_lock_sentinels_.size()); + EXPECT_FALSE(manager->wake_lock_); EXPECT_FALSE(system_lock.is_acquired()); }
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc index cbdc8be..7c9de8e 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc
@@ -8,14 +8,14 @@ #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/modules/event_target_modules_names.h" -#include "third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h" +#include "third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" namespace blink { WakeLockSentinel::WakeLockSentinel(ScriptState* script_state, WakeLockType type, - WakeLockStateRecord* manager) + WakeLockManager* manager) : ContextLifecycleObserver(ExecutionContext::From(script_state)), manager_(manager), type_(type) {}
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h index 30d954a..1acbfb4d 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h
@@ -19,7 +19,7 @@ class ExecutionContext; class ScriptState; -class WakeLockStateRecord; +class WakeLockManager; class MODULES_EXPORT WakeLockSentinel final : public EventTargetWithInlineData, @@ -31,7 +31,7 @@ public: WakeLockSentinel(ScriptState* script_state, WakeLockType type, - WakeLockStateRecord* manager); + WakeLockManager* manager); ~WakeLockSentinel() override; // Web-exposed interfaces @@ -51,7 +51,7 @@ void ContextDestroyed(ExecutionContext*) override; private: - friend class WakeLockStateRecord; + friend class WakeLockManager; // This function, which only has any effect once, detaches this sentinel from // its |manager_|, and fires a "release" event. @@ -61,7 +61,7 @@ // where |script_state_|'s context is no longer valid. void DoRelease(); - Member<WakeLockStateRecord> manager_; + Member<WakeLockManager> manager_; const WakeLockType type_; FRIEND_TEST_ALL_PREFIXES(WakeLockSentinelTest, MultipleReleaseCalls);
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc index 70cf9dd5..370f6e3 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
@@ -12,7 +12,7 @@ #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/events/native_event_listener.h" #include "third_party/blink/renderer/modules/event_target_modules_names.h" -#include "third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h" +#include "third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h" #include "third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "v8/include/v8.h" @@ -53,12 +53,12 @@ MockWakeLockService wake_lock_service; WakeLockTestingContext context(&wake_lock_service); - auto* state_record = MakeGarbageCollected<WakeLockStateRecord>( - context.GetDocument(), WakeLockType::kScreen); + auto* manager = MakeGarbageCollected<WakeLockManager>(context.GetDocument(), + WakeLockType::kScreen); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState()); ScriptPromise promise = resolver->Promise(); - state_record->AcquireWakeLock(resolver); + manager->AcquireWakeLock(resolver); context.WaitForPromiseFulfillment(promise); auto* sentinel = ScriptPromiseUtils::GetPromiseResolutionAsWakeLockSentinel(promise); @@ -87,8 +87,8 @@ auto* sentinel = MakeGarbageCollected<WakeLockSentinel>( context.GetScriptState(), WakeLockType::kScreen, - MakeGarbageCollected<WakeLockStateRecord>(context.GetDocument(), - WakeLockType::kScreen)); + MakeGarbageCollected<WakeLockManager>(context.GetDocument(), + WakeLockType::kScreen)); auto* event_listener = MakeGarbageCollected<SyncEventListener>(WTF::Bind([]() {
diff --git a/third_party/blink/renderer/modules/webtransport/BUILD.gn b/third_party/blink/renderer/modules/webtransport/BUILD.gn new file mode 100644 index 0000000..1e3507c --- /dev/null +++ b/third_party/blink/renderer/modules/webtransport/BUILD.gn
@@ -0,0 +1,31 @@ +# Copyright 2019 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("//third_party/blink/renderer/modules/modules.gni") + +blink_modules_sources("webtransport") { + sources = [ + "quic_transport.cc", + "quic_transport.h", + ] +} + +jumbo_source_set("unit_tests") { + testonly = true + sources = [] + + configs += [ + "//third_party/blink/renderer:config", + "//third_party/blink/renderer:inside_blink", + "//third_party/blink/renderer/core:blink_core_pch", + ] + + deps = [ + "//testing/gmock", + "//testing/gtest", + "//third_party/blink/renderer/modules", + "//third_party/blink/renderer/platform", + "//third_party/blink/renderer/platform/wtf", + ] +}
diff --git a/third_party/blink/renderer/modules/webtransport/OWNERS b/third_party/blink/renderer/modules/webtransport/OWNERS new file mode 100644 index 0000000..e57af91f --- /dev/null +++ b/third_party/blink/renderer/modules/webtransport/OWNERS
@@ -0,0 +1,5 @@ +ricea@chromium.org +yhirano@chromium.org + +# TEAM: blink-network-dev@chromium.org +# COMPONENT: Blink>Network>WebTransport
diff --git a/third_party/blink/renderer/modules/webtransport/README.md b/third_party/blink/renderer/modules/webtransport/README.md new file mode 100644 index 0000000..4014d4a --- /dev/null +++ b/third_party/blink/renderer/modules/webtransport/README.md
@@ -0,0 +1,8 @@ +# WebTransport API + +This is a directory for [Web Transport](https://wicg.github.io/web-transport/) +implementation. + +## Design docs + + - [QuicTransport](https://docs.google.com/document/d/1UgviRBnZkMUq4OKcsAJvIQFX6UCXeCbOtX_wMgwD_es/edit)
diff --git a/third_party/blink/renderer/modules/webtransport/quic_transport.cc b/third_party/blink/renderer/modules/webtransport/quic_transport.cc new file mode 100644 index 0000000..b9403846 --- /dev/null +++ b/third_party/blink/renderer/modules/webtransport/quic_transport.cc
@@ -0,0 +1,13 @@ +// Copyright 2019 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 "third_party/blink/renderer/modules/webtransport/quic_transport.h" + +namespace blink { + +QuicTransport::QuicTransport(ScriptState* script_state, const String& url) {} + +void QuicTransport::Dispose() {} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/webtransport/quic_transport.h b/third_party/blink/renderer/modules/webtransport/quic_transport.h new file mode 100644 index 0000000..c9262d6 --- /dev/null +++ b/third_party/blink/renderer/modules/webtransport/quic_transport.h
@@ -0,0 +1,34 @@ +// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_QUIC_TRANSPORT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_QUIC_TRANSPORT_H_ + +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" + +namespace blink { + +class ScriptState; + +class MODULES_EXPORT QuicTransport final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + USING_PRE_FINALIZER(QuicTransport, Dispose); + + public: + static QuicTransport* Create(ScriptState* script_state, const String& url) { + return MakeGarbageCollected<QuicTransport>(script_state, url); + } + + QuicTransport(ScriptState*, const String& url); + ~QuicTransport() override = default; + + private: + void Dispose(); +}; + +} // namespace blink + +#endif
diff --git a/third_party/blink/renderer/modules/webtransport/quic_transport.idl b/third_party/blink/renderer/modules/webtransport/quic_transport.idl new file mode 100644 index 0000000..469fc482 --- /dev/null +++ b/third_party/blink/renderer/modules/webtransport/quic_transport.idl
@@ -0,0 +1,16 @@ +// Copyright 2019 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. + +// https://wicg.github.io/web-transport/#quic-transport +[ + Constructor(USVString url), + Exposed=(Window, Worker), + RuntimeEnabled=QuicTransport, + ConstructorCallWith=ScriptState +] interface QuicTransport { + // QuicTransport is the first, and at this moment only, transport which is + // implemented. In the (draft) spec there are many mix-in interfaces which + // QuicTransport includes, but we define all their methods/attributes here + // for simplicity. +};
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 1f06f078..955f89e 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1255,6 +1255,7 @@ "p2p/socket_dispatcher.cc", "p2p/socket_dispatcher.h", "peerconnection/audio_codec_factory.cc", + "peerconnection/audio_codec_factory.h", "peerconnection/rtc_answer_options_platform.h", "peerconnection/rtc_dtmf_sender_handler.cc", "peerconnection/rtc_dtmf_sender_handler.h", @@ -1285,6 +1286,7 @@ "peerconnection/video_codec_factory.h", "peerconnection/webrtc_audio_sink.cc", "peerconnection/webrtc_video_track_source.cc", + "peerconnection/webrtc_video_track_source.h", "prerender.cc", "prerender.h", "prerender_client.h", @@ -2115,6 +2117,19 @@ ] } +# Fuzzer for blink::DateTimeFormat. +fuzzer_test("blink_date_time_format_fuzzer") { + sources = [ + "text/date_time_format_fuzzer.cc", + ] + deps = [ + ":blink_fuzzer_test_support", + ":platform", + ] + dict = "//testing/libfuzzer/fuzzers/dicts/date.dict" + seed_corpus = "text/date_time_format_fuzzer_seed_corpus" +} + # Fuzzer for blink::JSONParser. fuzzer_test("blink_json_parser_fuzzer") { sources = [
diff --git a/third_party/blink/renderer/platform/heap/finalizer_traits.h b/third_party/blink/renderer/platform/heap/finalizer_traits.h index d96e356..03ff1d9 100644 --- a/third_party/blink/renderer/platform/heap/finalizer_traits.h +++ b/third_party/blink/renderer/platform/heap/finalizer_traits.h
@@ -38,18 +38,27 @@ struct FinalizerTraitImpl<T, true> { private: STATIC_ONLY(FinalizerTraitImpl); - struct CustomDispatch { + struct Custom { static void Call(void* obj) { static_cast<T*>(obj)->FinalizeGarbageCollectedObject(); } }; - struct DestructorDispatch { - static void Call(void* obj) { static_cast<T*>(obj)->~T(); } + struct Destructor { + static void Call(void* obj) { +// The garbage collector differs from regular C++ here as it remembers whether +// an object's base class has a virtual destructor. In case there is no virtual +// destructor present, the object is always finalized through its leaf type. In +// other words: there is no finalization through a base pointer. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdelete-non-abstract-non-virtual-dtor" + static_cast<T*>(obj)->~T(); +#pragma GCC diagnostic pop + } }; using FinalizeImpl = std::conditional_t<HasFinalizeGarbageCollectedObject<T>::value, - CustomDispatch, - DestructorDispatch>; + Custom, + Destructor>; public: static void Finalize(void* obj) {
diff --git a/third_party/blink/renderer/platform/heap/gc_info.h b/third_party/blink/renderer/platform/heap/gc_info.h index fa960e46..36b53cc 100644 --- a/third_party/blink/renderer/platform/heap/gc_info.h +++ b/third_party/blink/renderer/platform/heap/gc_info.h
@@ -93,11 +93,9 @@ Mutex table_mutex_; }; -// GCInfoAtBaseType should be used when returning a unique 14 bit integer -// for a given gcInfo. template <typename T> -struct GCInfoAtBaseType { - STATIC_ONLY(GCInfoAtBaseType); +struct GCInfoTrait { + STATIC_ONLY(GCInfoTrait); static uint32_t Index() { static_assert(sizeof(T), "T must be fully defined"); static const GCInfo kGcInfo = { @@ -117,31 +115,6 @@ } }; -template <typename T, - bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type, - GarbageCollected>::value> -struct GetGarbageCollectedType; - -template <typename T> -struct GetGarbageCollectedType<T, true> { - STATIC_ONLY(GetGarbageCollectedType); - using type = typename T::GarbageCollectedType; -}; - -template <typename T> -struct GetGarbageCollectedType<T, false> { - STATIC_ONLY(GetGarbageCollectedType); - using type = T; -}; - -template <typename T> -struct GCInfoTrait { - STATIC_ONLY(GCInfoTrait); - static uint32_t Index() { - return GCInfoAtBaseType<typename GetGarbageCollectedType<T>::type>::Index(); - } -}; - template <typename U> class GCInfoTrait<const U> : public GCInfoTrait<U> {};
diff --git a/third_party/blink/renderer/platform/heap/heap.cc b/third_party/blink/renderer/platform/heap/heap.cc index af6f4b3..02abf6859 100644 --- a/third_party/blink/renderer/platform/heap/heap.cc +++ b/third_party/blink/renderer/platform/heap/heap.cc
@@ -585,7 +585,8 @@ reinterpret_cast<v8::EmbedderHeapTracer*>( thread_state_->unified_heap_controller()); while (v8_references.Pop(&reference)) { - controller->RegisterEmbedderReference(reference->Get()); + controller->RegisterEmbedderReference( + reference->template Cast<v8::Data>().Get()); } }
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h index e5a7316a..fd05b97 100644 --- a/third_party/blink/renderer/platform/heap/heap.h +++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -518,22 +518,48 @@ #endif public: - using GarbageCollectedType = T; + using ParentMostGarbageCollectedType = T; void* operator new(size_t size) = delete; // Must use MakeGarbageCollected. + template <typename Derived> static void* AllocateObject(size_t size) { if (IsGarbageCollectedMixin<T>::value) { // Ban large mixin so we can use PageFromObject() on them. CHECK_GE(kLargeObjectSizeThreshold, size) << "GarbageCollectedMixin may not be a large object"; } - return ThreadHeap::Allocate<T>(size); + return ThreadHeap::Allocate<GCInfoFoldedType<Derived>>(size); } void operator delete(void* p) { NOTREACHED(); } protected: + // This trait in theory can be moved to gc_info.h, but that would cause + // significant memory bloat caused by huge number of ThreadHeap::Allocate<> + // instantiations, which linker is not able to fold. + template <typename Derived> + class GCInfoFolded { + static constexpr bool is_virtual_destructor_at_base = + std::has_virtual_destructor<ParentMostGarbageCollectedType>::value; + static constexpr bool both_trivially_destructible = + std::is_trivially_destructible<ParentMostGarbageCollectedType>::value && + std::is_trivially_destructible<Derived>::value; + static constexpr bool has_custom_dispatch_at_base = + internal::HasFinalizeGarbageCollectedObject< + ParentMostGarbageCollectedType>::value; + + public: + using Type = std::conditional_t<is_virtual_destructor_at_base || + both_trivially_destructible || + has_custom_dispatch_at_base, + ParentMostGarbageCollectedType, + Derived>; + }; + + template <typename Derived> + using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type; + GarbageCollected() = default; DISALLOW_COPY_AND_ASSIGN(GarbageCollected); @@ -552,7 +578,7 @@ internal::HasFinalizeGarbageCollectedObject<T>::value, "Finalized GarbageCollected class should either have a virtual " "destructor or be marked as final."); - void* memory = T::AllocateObject(sizeof(T)); + void* memory = T::template AllocateObject<T>(sizeof(T)); HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory); // Placement new as regular operator new() is deleted. T* object = ::new (memory) T(std::forward<Args>(args)...); @@ -579,7 +605,8 @@ internal::HasFinalizeGarbageCollectedObject<T>::value, "Finalized GarbageCollected class should either have a virtual " "destructor or be marked as final."); - void* memory = T::AllocateObject(sizeof(T) + additional_bytes.value); + void* memory = + T::template AllocateObject<T>(sizeof(T) + additional_bytes.value); HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory); // Placement new as regular operator new() is deleted. T* object = ::new (memory) T(std::forward<Args>(args)...);
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h index 351f61f..ba203d3 100644 --- a/third_party/blink/renderer/platform/heap/heap_allocator.h +++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -510,6 +510,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { return ThreadHeap::Allocate< HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>( @@ -539,6 +540,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { return ThreadHeap::Allocate<HeapHashSet<ValueArg, HashArg, TraitsArg>>( size); @@ -568,6 +570,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { return ThreadHeap::Allocate< HeapLinkedHashSet<ValueArg, HashArg, TraitsArg>>(size); @@ -601,6 +604,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { return ThreadHeap::Allocate< HeapListHashSet<ValueArg, inlineCapacity, HashArg>>(size); @@ -629,6 +633,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { return ThreadHeap::Allocate< HeapHashCountedSet<Value, HashFunctions, Traits>>(size); @@ -655,6 +660,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { // On-heap HeapVectors generally should not have inline capacity, but it is // hard to avoid when using a type alias. Hence we only disallow the @@ -706,6 +712,7 @@ } public: + template <typename> static void* AllocateObject(size_t size) { // On-heap HeapDeques generally should not have inline capacity, but it is // hard to avoid when using a type alias. Hence we only disallow the
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc index 54b950c..478fac4e 100644 --- a/third_party/blink/renderer/platform/heap/heap_test.cc +++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -6100,4 +6100,24 @@ } } +class GCBase : public GarbageCollected<GCBase> { + public: + virtual void Trace(Visitor*) {} +}; + +class GCDerived final : public GCBase { + public: + static int destructor_called; + void Trace(Visitor*) override {} + ~GCDerived() { ++destructor_called; } +}; + +int GCDerived::destructor_called = 0; + +TEST_F(HeapTest, CallMostDerivedFinalizer) { + MakeGarbageCollected<GCDerived>(); + PreciselyCollectGarbage(); + EXPECT_EQ(1, GCDerived::destructor_called); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc index 69523852..874cfa1 100644 --- a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc +++ b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc
@@ -40,7 +40,8 @@ v8_references_worklist_.Push(&v8_reference); return; } - controller_->RegisterEmbedderReference(v8_reference.Get()); + controller_->RegisterEmbedderReference( + v8_reference.template Cast<v8::Data>().Get()); } UnifiedHeapMarkingVisitor::UnifiedHeapMarkingVisitor(ThreadState* thread_state,
diff --git a/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.cc b/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.cc index abbae4c11..0165a9b 100644 --- a/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.cc +++ b/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/public/platform/modules/peerconnection/audio_codec_factory.h" +#include "third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h" #include <memory> #include <vector>
diff --git a/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h b/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h new file mode 100644 index 0000000..a528ac8 --- /dev/null +++ b/third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h
@@ -0,0 +1,23 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_AUDIO_CODEC_FACTORY_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_AUDIO_CODEC_FACTORY_H_ + +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/webrtc/api/audio_codecs/audio_decoder_factory.h" +#include "third_party/webrtc/api/audio_codecs/audio_encoder_factory.h" +#include "third_party/webrtc/api/scoped_refptr.h" + +namespace blink { + +PLATFORM_EXPORT rtc::scoped_refptr<webrtc::AudioEncoderFactory> +CreateWebrtcAudioEncoderFactory(); + +PLATFORM_EXPORT rtc::scoped_refptr<webrtc::AudioDecoderFactory> +CreateWebrtcAudioDecoderFactory(); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_AUDIO_CODEC_FACTORY_H_
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc index a43ed373..f7d1583 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc
@@ -181,9 +181,9 @@ int32_t Decode(uint32_t timestamp) { webrtc::EncodedImage input_image; - input_image.Allocate(1); - input_image.set_size(1); - input_image.data()[0] = 0; + static const uint8_t data[1] = {0}; + input_image.SetEncodedData( + webrtc::EncodedImageBuffer::Create(data, sizeof(data))); input_image._frameType = webrtc::VideoFrameType::kVideoFrameKey; input_image._completeFrame = true; input_image.SetTimestamp(timestamp); @@ -214,7 +214,9 @@ webrtc::EncodedImage GetEncodedImageWithColorSpace(uint32_t timestamp) { webrtc::EncodedImage input_image; - input_image.Allocate(1); + static const uint8_t data[1] = {0}; + input_image.SetEncodedData( + webrtc::EncodedImageBuffer::Create(data, sizeof(data))); input_image.set_size(1); input_image.data()[0] = 0; input_image._completeFrame = true;
diff --git a/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc b/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc index 9ce0d60..e1020d02 100644 --- a/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc +++ b/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc
@@ -10,10 +10,10 @@ #include "base/cpu.h" #include "base/logging.h" #include "base/system/sys_info.h" -#include "third_party/blink/public/platform/modules/peerconnection/audio_codec_factory.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/media_capabilities/web_media_configuration.h" #include "third_party/blink/renderer/platform/media_capabilities/web_video_configuration.h" +#include "third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h" #include "third_party/blink/renderer/platform/peerconnection/video_codec_factory.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" #include "third_party/webrtc/api/audio_codecs/audio_encoder_factory.h"
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc index 1698102..9c5bc18e 100644 --- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc +++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/public/platform/modules/peerconnection/webrtc_video_track_source.h" +#include "third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h" #include "base/bind.h" #include "base/bind_helpers.h"
diff --git a/third_party/blink/public/platform/modules/peerconnection/webrtc_video_track_source.h b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h similarity index 84% rename from third_party/blink/public/platform/modules/peerconnection/webrtc_video_track_source.h rename to third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h index 934e1cd..bb02e3e4 100644 --- a/third_party/blink/public/platform/modules/peerconnection/webrtc_video_track_source.h +++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEBRTC_VIDEO_TRACK_SOURCE_H_ -#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEBRTC_VIDEO_TRACK_SOURCE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_WEBRTC_VIDEO_TRACK_SOURCE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_WEBRTC_VIDEO_TRACK_SOURCE_H_ #include "base/memory/scoped_refptr.h" #include "base/threading/thread_checker.h" #include "media/base/video_frame_pool.h" -#include "third_party/blink/public/platform/web_common.h" +#include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/webrtc/media/base/adapted_video_track_source.h" #include "third_party/webrtc/rtc_base/timestamp_aligner.h" @@ -18,10 +18,7 @@ // the webrtc video pipeline, each received a media::VideoFrame is converted to // a webrtc::VideoFrame, taking any adaptation requested by downstream classes // into account. -// -// TODO(crbug.com/787254): Move this class out of the Blink exposed API when its -// clients get Onion soup'ed. -class BLINK_PLATFORM_EXPORT WebRtcVideoTrackSource +class PLATFORM_EXPORT WebRtcVideoTrackSource : public rtc::AdaptedVideoTrackSource { public: struct FrameAdaptationParams { @@ -88,4 +85,4 @@ } // namespace blink -#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_WEBRTC_VIDEO_TRACK_SOURCE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_WEBRTC_VIDEO_TRACK_SOURCE_H_
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc index 5d339e4..343b0ff 100644 --- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc +++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
@@ -10,7 +10,7 @@ #include "media/base/video_frame.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/platform/modules/peerconnection/webrtc_video_track_source.h" +#include "third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h" #include "third_party/blink/renderer/platform/testing/video_frame_utils.h" #include "third_party/webrtc/api/video/video_frame.h" #include "third_party/webrtc/rtc_base/ref_counted_object.h"
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 82e3dde7..da9b3b1 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1344,6 +1344,10 @@ status: "experimental", }, { + name: "QuicTransport", + status: "experimental", + }, + { name: "ReducedReferrerGranularity", }, {
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer.cc b/third_party/blink/renderer/platform/text/date_time_format_fuzzer.cc new file mode 100644 index 0000000..3064f62a --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer.cc
@@ -0,0 +1,38 @@ +// Copyright 2019 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 "third_party/blink/renderer/platform/text/date_time_format.h" + +#include <stddef.h> +#include <stdint.h> +#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class DummyTokenHandler : public DateTimeFormat::TokenHandler { + public: + ~DummyTokenHandler() override = default; + + void VisitField(DateTimeFormat::FieldType field_type, int count) override { + CHECK(field_type != DateTimeFormat::FieldType::kFieldTypeInvalid); + CHECK_GE(count, 1); + } + + void VisitLiteral(const WTF::String& string) override { + CHECK_GT(string.length(), 0u); + } +}; + +} // namespace blink + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + static blink::BlinkFuzzerTestSupport test_support = + blink::BlinkFuzzerTestSupport(); + blink::DummyTokenHandler handler; + blink::DateTimeFormat::Parse( + WTF::String::FromUTF8(reinterpret_cast<const char*>(data), size), + handler); + return 0; +}
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/a b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/a new file mode 100644 index 0000000..09f23df --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/a
@@ -0,0 +1 @@ +yyyy.MM.dd G 'at' HH:mm:ss zzz
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/b b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/b new file mode 100644 index 0000000..a1deed7 --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/b
@@ -0,0 +1 @@ +EEE, MMM d, ''yy
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/c b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/c new file mode 100644 index 0000000..a8eeb2a --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/c
@@ -0,0 +1 @@ +h:mm a
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/d b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/d new file mode 100644 index 0000000..53bbe75b --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/d
@@ -0,0 +1 @@ +hh 'o''clock' a, zzzz
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/e b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/e new file mode 100644 index 0000000..1840423 --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/e
@@ -0,0 +1 @@ +K:mm a, z
diff --git a/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/f b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/f new file mode 100644 index 0000000..b26f515 --- /dev/null +++ b/third_party/blink/renderer/platform/text/date_time_format_fuzzer_seed_corpus/f
@@ -0,0 +1 @@ +yyyyy.MMMM.dd GGG hh:mm aaa
diff --git a/third_party/blink/tools/BUILD.gn b/third_party/blink/tools/BUILD.gn index f02b590..e59f75ef 100644 --- a/third_party/blink/tools/BUILD.gn +++ b/third_party/blink/tools/BUILD.gn
@@ -2,51 +2,16 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# This action generates WPT metadata files for skipping web tests -action("build_wpt_metadata") { - testonly = true - script = "//third_party/blink/tools/build_wpt_metadata.py" - args = [ - "--metadata-output-dir", - rebase_path("$root_out_dir/wpt_expectations_metadata"), - "--additional-expectations", - "../../third_party/blink/web_tests/WPTOverrideExpectations", - ] - outputs = [ - "$root_out_dir/wpt_expectations_metadata.stamp", - ] - data = [ - # Include the blinkpy tools to access expectations data - "//third_party/blink/tools/blinkpy/", - ] - inputs = [ - # Include the various Test Expectations files - "//third_party/blink/web_tests/ASANExpectations", - "//third_party/blink/web_tests/LeakExpectations", - "//third_party/blink/web_tests/MSANExpectations", - "//third_party/blink/web_tests/NeverFixTests", - "//third_party/blink/web_tests/SlowTests", - "//third_party/blink/web_tests/StaleTestExpectations", - "//third_party/blink/web_tests/TestExpectations", - "//third_party/blink/web_tests/VirtualTestSuites", - "//third_party/blink/web_tests/WPTOverrideExpectations", - ] -} - # WPT codebase for running webplatform tests group("wpt_tests_isolate") { testonly = true - data_deps = [ - ":build_wpt_metadata", - # Note that we also depend on Chrome and Chromedriver here but specify those - # via the //wpt_tests_isolate target in //src/BUILD.gn - ] data = [ "//testing/scripts/common.py", "//testing/scripts/run_wpt_tests.py", "//testing/xvfb.py", - # Include blinkpy tools for post-processing WPT output. + # Include blinkpy tools for setting up expectations. + "//third_party/blink/tools/build_wpt_metadata.py", "//third_party/blink/tools/update_wpt_output.py", "//third_party/blink/tools/blinkpy/",
diff --git a/third_party/blink/web_tests/ASANExpectations b/third_party/blink/web_tests/ASANExpectations index 60b1bc0..551217e 100644 --- a/third_party/blink/web_tests/ASANExpectations +++ b/third_party/blink/web_tests/ASANExpectations
@@ -71,3 +71,5 @@ # Sheriff 2019-07-31 crbug.com/989365 [ Linux ] external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.tentative.https.html [ Pass Timeout ] + +crbug.com/1015737 [ Linux ] external/wpt/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html [ Crash ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index e9be992..d6bbb62 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2475,8 +2475,6 @@ crbug.com/955620 http/tests/navigation/frozen-useragent.html [ Skip ] crbug.com/955620 virtual/stable/http/tests/navigation/frozen-useragent.html [ Skip ] -crbug.com/863896 http/tests/permissions/test-query.html [ Timeout ] - crbug.com/876485 fast/performance/performance-measure-null-exception.html [ Failure ] crbug.com/713587 external/wpt/css/css-ui/caret-color-006.html [ Skip ] @@ -5769,3 +5767,6 @@ crbug.com/1014950 [ Mac ] http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-no-url-end-to-end.js [ Pass Timeout ] crbug.com/1014950 [ Mac ] virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-no-url-end-to-end.js [ Pass Timeout ] crbug.com/1015187 [ Linux Mac ] virtual/cross-origin-embedder-policy/external/wpt/html/cross-origin-embedder-policy/none.https.html [ Pass Failure ] + +# Sheriff 2019-10-18 +crbug.com/996250 external/wpt/web-nfc/NFCReader_scan_iframe.https.html [ Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index efb5506..c2caca7 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -747,9 +747,16 @@ "--site-per-process"] }, { + "prefix": "split-http-cache-not-site-per-process", + "base": "http/tests/devtools/isolated-code-cache", + "args": ["--enable-features=SplitCacheByNetworkIsolationKey", + "--disable-site-isolation-trials"] + }, + { "prefix": "not-site-per-process", "base": "http/tests/devtools/isolated-code-cache", - "args": ["--disable-site-isolation-trials"] + "args": ["--disable-site-isolation-trials", + "--disable-features=SplitCacheByNetworkIsolationKey"] }, { "prefix": "not-site-per-process",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index 2572923..93d7205f 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -155740,9 +155740,15 @@ "html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_4-expected.txt": [ [] ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html": [ + [] + ], "html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window-expected.txt": [ [] ], + "html/browsers/the-window-object/named-access-on-the-window-object/prototype-expected.txt": [ + [] + ], "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [ [] ], @@ -199203,6 +199209,262 @@ {} ] ], + "compression/compression-bad-chunks.any.js": [ + [ + "compression/compression-bad-chunks.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-bad-chunks.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-bad-chunks.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-bad-chunks.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ] + ], + "compression/compression-including-empty-chunk.any.js": [ + [ + "compression/compression-including-empty-chunk.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-including-empty-chunk.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-including-empty-chunk.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-including-empty-chunk.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "compression/compression-multiple-chunks.any.js": [ + [ + "compression/compression-multiple-chunks.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-multiple-chunks.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-multiple-chunks.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-multiple-chunks.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "compression/compression-output-length.any.js": [ + [ + "compression/compression-output-length.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-output-length.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-output-length.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-output-length.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ] + ], "compression/compression-stream.any.js": [ [ "compression/compression-stream.any.html", @@ -242678,6 +242940,12 @@ {} ] ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html": [ + [ + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html", + {} + ] + ], "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html": [ [ "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html", @@ -242697,6 +242965,12 @@ } ] ], + "html/browsers/the-window-object/named-access-on-the-window-object/prototype.html": [ + [ + "html/browsers/the-window-object/named-access-on-the-window-object/prototype.html", + {} + ] + ], "html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html": [ [ "html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html", @@ -340284,6 +340558,22 @@ "1d3965fca6769c70bc02308a4c70b4e58c8990e5", "reftest" ], + "compression/compression-bad-chunks.any.js": [ + "06e3be9c0fe6d5663acf07cff12c4b9903c24661", + "testharness" + ], + "compression/compression-including-empty-chunk.any.js": [ + "eff928857903890e967fdbcab042a44a0731e946", + "testharness" + ], + "compression/compression-multiple-chunks.any.js": [ + "ca49b9cf42766a072b57cc8eb3f083127d90f8c4", + "testharness" + ], + "compression/compression-output-length.any.js": [ + "d7dafcd10092d5fd1135cbb4ca2d82d5844f6d08", + "testharness" + ], "compression/compression-stream.any.js": [ "47df70f7cd3979c1a3eab45581376fd38a6b2367", "testharness" @@ -384849,11 +385139,11 @@ "visual" ], "css/css-lists/content-property/marker-text-matches-armenian-ref.html": [ - "f21dfff69608a6a1201bd586c2a6e1e24d5fd915", + "de55b7381ac1e2cf1553adcaee916e24e7348c4c", "support" ], "css/css-lists/content-property/marker-text-matches-armenian.html": [ - "fd0df631149a740a201510f2edff405d28f41929", + "58f570cd1197579aba1b646a1c970ab13c23c3e3", "reftest" ], "css/css-lists/content-property/marker-text-matches-circle-ref.html": [ @@ -443828,6 +444118,14 @@ "f266dd7acb96cc473129c066e59f027c2eb067f0", "testharness" ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html": [ + "2acad0734cda6a5076e836240cec107af036a72a", + "testharness" + ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html": [ + "9d7b9f8a25ecc392abd74949a1362c8b13450a9d", + "support" + ], "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html": [ "d5b1789d59455603d1f5929a7a7f05d8a7218d52", "testharness" @@ -443840,6 +444138,14 @@ "59d94efc994e365301c20dbc5ff1b14409dfcaab", "testharness" ], + "html/browsers/the-window-object/named-access-on-the-window-object/prototype-expected.txt": [ + "312d0a1aa5fc22cd30618476df4a5538d1b4af50", + "support" + ], + "html/browsers/the-window-object/named-access-on-the-window-object/prototype.html": [ + "910374381be85e5b37e1f343b6070ce7a776fe2b", + "testharness" + ], "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [ "c3b3cc185255d159b0f9ff9fd97aae71170d0af6", "support" @@ -449609,7 +449915,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js": [ @@ -449633,7 +449939,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-domain.sub.html": [ @@ -449649,7 +449955,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html": [ @@ -449657,7 +449963,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html": [ @@ -449689,7 +449995,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html": [ @@ -449697,7 +450003,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html": [ @@ -449705,7 +450011,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html": [ @@ -449713,7 +450019,7 @@ "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers": [ - "1528bf05e6368b00600b23c23042bf0d61985917", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", "support" ], "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js": [ @@ -450137,7 +450443,7 @@ "support" ], "html/interaction/focus/the-autofocus-attribute/resources/utils.js": [ - "0eeb5a9f0adf1d09959227241cd71fe32ebb485c", + "c4f38fcb209e52328429a5d425fd5b5c8f2aaae4", "support" ], "html/interaction/focus/the-autofocus-attribute/same-origin-autofocus.html": [ @@ -450169,7 +450475,7 @@ "testharness" ], "html/interaction/focus/the-autofocus-attribute/update-the-rendering.html": [ - "afaf0926f5b55e4f1925010c7262ed26a616d3be", + "dcee4c16a07d9f5c622e562b7807e5788102fa13", "testharness" ], "html/obsolete/META.yml": [ @@ -463465,7 +463771,7 @@ "support" ], "interfaces/reporting.idl": [ - "05d5a42458b5cd38c4a902b5a7066af524a396fc", + "f5370e8f1e656acf7409dbda907ee9672d5e8ed1", "support" ], "interfaces/requestidlecallback.idl": [ @@ -491697,7 +492003,7 @@ "testharness" ], "reporting/idlharness.any-expected.txt": [ - "2852fc5895a9b4e8fccf5c53619cdb79fb399587", + "55b27a0ceb464800e872eda9f44207f755d5beea", "support" ], "reporting/idlharness.any.js": [ @@ -491705,7 +492011,7 @@ "testharness" ], "reporting/idlharness.any.worker-expected.txt": [ - "2d07eecf67cc89acc3cf03366b39e9fb2cb3611a", + "ce631f117aeb43da8384f991a9305c63bf527223", "support" ], "reporting/idlharness.window-expected.txt": [ @@ -492505,7 +492811,7 @@ "support" ], "resources/chromium/nfc-mock.js": [ - "30645fb00dd924085cf2dc83325d2a579dec44ed", + "6ef03b390d8df7df8abd7662e037db6bdf5febce", "support" ], "resources/chromium/sensor.mojom.js": [ @@ -512197,7 +512503,7 @@ "testharness" ], "web-nfc/NFCReader_scan_iframe.https.html": [ - "1f29fe4b41d9028a2381210b8b3d9ccba598b9b2", + "31e79b0388aa5f407a7c9a1b591f162b3e42001f", "testharness" ], "web-nfc/NFCReadingEvent_constructor.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/compression/compression-bad-chunks.any.js b/third_party/blink/web_tests/external/wpt/compression/compression-bad-chunks.any.js new file mode 100644 index 0000000..06e3be9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/compression/compression-bad-chunks.any.js
@@ -0,0 +1,62 @@ +// META: global=worker + +'use strict'; + +const badChunks = [ + { + name: 'undefined', + value: undefined + }, + { + name: 'null', + value: null + }, + { + name: 'numeric', + value: 3.14 + }, + { + name: 'object, not BufferSource', + value: {} + }, + { + name: 'array', + value: [65] + }, + { + name: 'SharedArrayBuffer', + // Use a getter to postpone construction so that all tests don't fail where + // SharedArrayBuffer is not yet implemented. + get value() { + return new SharedArrayBuffer(); + } + }, + { + name: 'shared Uint8Array', + get value() { + return new Uint8Array(new SharedArrayBuffer()) + } + }, +]; + +for (const chunk of badChunks) { + promise_test(async t => { + const cs = new CompressionStream('gzip'); + const reader = cs.readable.getReader(); + const writer = cs.writable.getWriter(); + const writePromise = writer.write(chunk.value); + const readPromise = reader.read(); + await promise_rejects(t, new TypeError(), writePromise, 'write should reject'); + await promise_rejects(t, new TypeError(), readPromise, 'read should reject'); + }, `chunk of type ${chunk.name} should error the stream for gzip`); + + promise_test(async t => { + const cs = new CompressionStream('deflate'); + const reader = cs.readable.getReader(); + const writer = cs.writable.getWriter(); + const writePromise = writer.write(chunk.value); + const readPromise = reader.read(); + await promise_rejects(t, new TypeError(), writePromise, 'write should reject'); + await promise_rejects(t, new TypeError(), readPromise, 'read should reject'); + }, `chunk of type ${chunk.name} should error the stream for deflate`); +}
diff --git a/third_party/blink/web_tests/external/wpt/compression/compression-including-empty-chunk.any.js b/third_party/blink/web_tests/external/wpt/compression/compression-including-empty-chunk.any.js new file mode 100644 index 0000000..eff9288 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/compression/compression-including-empty-chunk.any.js
@@ -0,0 +1,57 @@ +// META: global=worker +// META: script=pako/pako_inflate.min.js +// META: timeout=long + +'use strict'; + +// This test asserts that compressing '' doesn't affect the compressed data. +// Example: compressing ['Hello', '', 'Hello'] results in 'HelloHello' + +async function compressChunkList(chunkList, format) { + const cs = new CompressionStream(format); + const writer = cs.writable.getWriter(); + for (const chunk of chunkList) { + const chunkByte = new TextEncoder().encode(chunk); + writer.write(chunkByte); + } + const closePromise = writer.close(); + const out = []; + const reader = cs.readable.getReader(); + let totalSize = 0; + while (true) { + const { value, done } = await reader.read(); + if (done) + break; + out.push(value); + totalSize += value.byteLength; + } + await closePromise; + const concatenated = new Uint8Array(totalSize); + let offset = 0; + for (const array of out) { + concatenated.set(array, offset); + offset += array.byteLength; + } + return concatenated; +} + +const chunkLists = [ + ['', 'Hello', 'Hello'], + ['Hello', '', 'Hello'], + ['Hello', 'Hello', ''] +]; +const expectedValue = new TextEncoder().encode('HelloHello'); + +for (const chunkList of chunkLists) { + promise_test(async t => { + const compressedData = await compressChunkList(chunkList, 'deflate'); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `the result of compressing [${chunkList}] with deflate should be 'HelloHello'`); + + promise_test(async t => { + const compressedData = await compressChunkList(chunkList, 'gzip'); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `the result of compressing [${chunkList}] with gzip should be 'HelloHello'`); +}
diff --git a/third_party/blink/web_tests/external/wpt/compression/compression-multiple-chunks.any.js b/third_party/blink/web_tests/external/wpt/compression/compression-multiple-chunks.any.js new file mode 100644 index 0000000..ca49b9cf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/compression/compression-multiple-chunks.any.js
@@ -0,0 +1,60 @@ +// META: global=worker +// META: script=pako/pako_inflate.min.js +// META: timeout=long + +'use strict'; + +// This test asserts that compressing multiple chunks should work. + +// Example: ('Hello', 3) => TextEncoder().encode('HelloHelloHello') +function makeExpectedChunk(input, numberOfChunks) { + const expectedChunk = input.repeat(numberOfChunks); + return new TextEncoder().encode(expectedChunk); +} + +// Example: ('Hello', 3, 'deflate') => compress ['Hello', 'Hello', Hello'] +async function compressMultipleChunks(input, numberOfChunks, format) { + const cs = new CompressionStream(format); + const writer = cs.writable.getWriter(); + const chunk = new TextEncoder().encode(input); + for (let i = 0; i < numberOfChunks; ++i) { + writer.write(chunk); + } + const closePromise = writer.close(); + const out = []; + const reader = cs.readable.getReader(); + let totalSize = 0; + while (true) { + const { value, done } = await reader.read(); + if (done) + break; + out.push(value); + totalSize += value.byteLength; + } + await closePromise; + const concatenated = new Uint8Array(totalSize); + let offset = 0; + for (const array of out) { + concatenated.set(array, offset); + offset += array.byteLength; + } + return concatenated; +} + +const hello = 'Hello'; + +for (let numberOfChunks = 2; numberOfChunks <= 16; ++numberOfChunks) { + promise_test(async t => { + const compressedData = await compressMultipleChunks(hello, numberOfChunks, 'deflate'); + const expectedValue = makeExpectedChunk(hello, numberOfChunks); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `compressing ${numberOfChunks} chunks with deflate should work`); + + promise_test(async t => { + const compressedData = await compressMultipleChunks(hello, numberOfChunks, 'gzip'); + const expectedValue = makeExpectedChunk(hello, numberOfChunks); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `compressing ${numberOfChunks} chunks with gzip should work`); +}
diff --git a/third_party/blink/web_tests/external/wpt/compression/compression-output-length.any.js b/third_party/blink/web_tests/external/wpt/compression/compression-output-length.any.js new file mode 100644 index 0000000..d7dafcd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/compression/compression-output-length.any.js
@@ -0,0 +1,54 @@ +// META: global=worker + +'use strict'; + +// This test asserts that compressed data length is shorter than the original +// data length. If the input is extremely small, the compressed data may be +// larger than the original data. + +const LARGE_FILE = '/media/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm'; + +async function compressArrayBuffer(input, format) { + const cs = new CompressionStream(format); + const writer = cs.writable.getWriter(); + writer.write(input); + const closePromise = writer.close(); + const out = []; + const reader = cs.readable.getReader(); + let totalSize = 0; + while (true) { + const { value, done } = await reader.read(); + if (done) + break; + out.push(value); + totalSize += value.byteLength; + } + await closePromise; + const concatenated = new Uint8Array(totalSize); + let offset = 0; + for (const array of out) { + concatenated.set(array, offset); + offset += array.byteLength; + } + return concatenated; +} + +promise_test(async () => { + const response = await fetch(LARGE_FILE); + const buffer = await response.arrayBuffer(); + const bufferView = new Uint8Array(buffer); + const originalLength = bufferView.length; + const compressedData = await compressArrayBuffer(bufferView, 'deflate'); + const compressedLength = compressedData.length; + assert_less_than(compressedLength, originalLength, 'output should be smaller'); +}, 'the length of deflated data should be shorter than that of the original data'); + +promise_test(async () => { + const response = await fetch(LARGE_FILE); + const buffer = await response.arrayBuffer(); + const bufferView = new Uint8Array(buffer); + const originalLength = bufferView.length; + const compressedData = await compressArrayBuffer(bufferView, 'gzip'); + const compressedLength = compressedData.length; + assert_less_than(compressedLength, originalLength, 'output should be smaller'); +}, 'the length of gzipped data should be shorter than that of the original data');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian-ref.html index f21dfff..de55b738 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian-ref.html
@@ -7,4 +7,4 @@ padding: 0; } </style> -<p>Ô±. Filler Text +<p>Ô±. Filler Text<span style="display: inline-block; width: 1px; height: 50px;"></span>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian.html b/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian.html index fd0df63..58f570c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian.html +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/content-property/marker-text-matches-armenian.html
@@ -14,5 +14,5 @@ </style> <ol> - <li>Filler Text</li> + <li>Filler Text<span style="display: inline-block; width: 1px; height: 50px;"></span></li> </ol>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html new file mode 100644 index 0000000..2acad07 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html
@@ -0,0 +1,38 @@ +<!doctype html> +<meta charset=utf-8> +<title>Named access across globals</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement("iframe"); + iframe.src = "cross-global-support.html"; + document.body.appendChild(iframe); + iframe.onload = this.step_func_done(function() { + var name = "named"; + var win = iframe.contentWindow; + var element = win.document.getElementById(name); + + var expectedValues = [ + // [value, is own property] + [element, false, "window"], + [element, false, "Window.prototype"], + [element, true, "named prototype object"], + [undefined, false, "EventTarget.prototype"], + [undefined, false, "Object.prototype"], + ]; + for (var object = win; object; object = Object.getPrototypeOf(object)) { + var expected = expectedValues.shift(); + assert_equals(object[name], expected[0], "[[Get]] on " + expected[2]); + var desc = Object.getOwnPropertyDescriptor(object, name); + if (expected[1]) { + assert_not_equals(desc, undefined, "[[GetOwnProperty]] on " + expected[2] + " should return something"); + assert_equals(desc.value, element, "[[GetOwnProperty]] on " + expected[2]); + } else { + assert_equals(desc, undefined, "[[GetOwnProperty]] on " + expected[2]); + } + } + }); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html new file mode 100644 index 0000000..9d7b9f8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html
@@ -0,0 +1,4 @@ +<!doctype html> +<meta charset=utf-8> +<title>Named access across globals: support file</title> +<span id="named"></span>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/prototype-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/prototype-expected.txt new file mode 100644 index 0000000..312d0a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/prototype-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +PASS Property on window. +PASS Property on Window.prototype. +FAIL Property on EventTarget.prototype. assert_equals: expected (undefined) undefined but got (object) object "[object Object]" +FAIL Property on Object.prototype. assert_equals: expected (undefined) undefined but got (object) object "[object Object]" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html new file mode 100644 index 0000000..9103743 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html
@@ -0,0 +1,94 @@ +<!doctype html> +<meta charset=utf-8> +<title>Named access with shadowing properties</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var name = "named1"; + window[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name).value, "shadowing"); + + assert_equals(Window.prototype[name], element); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name), undefined); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], element); + assert_equals(Object.getOwnPropertyDescriptor(npo, name).value, element); + + assert_equals(EventTarget.prototype[name], undefined); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name), undefined); +}, "Property on window."); + +test(function() { + var name = "named2"; + Window.prototype[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name), undefined); + + assert_equals(Window.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name).value, "shadowing"); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], element); + assert_equals(Object.getOwnPropertyDescriptor(npo, name).value, element); + + assert_equals(EventTarget.prototype[name], undefined); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name), undefined); +}, "Property on Window.prototype."); + +test(function() { + var name = "named3"; + EventTarget.prototype[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name), undefined); + + assert_equals(Window.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name), undefined); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(npo, name), undefined); + + assert_equals(EventTarget.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name).value, "shadowing"); +}, "Property on EventTarget.prototype."); + +test(function() { + var name = "named4"; + Object.prototype[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name), undefined); + + assert_equals(Window.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name), undefined); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(npo, name), undefined); + + assert_equals(EventTarget.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name), undefined); + + assert_equals(Object.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Object.prototype, name).value, "shadowing"); +}, "Property on Object.prototype."); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers index 1528bf0..4e798cd9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers
@@ -1,2 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp -Cross-Origin-Resource-Policy: cross-site +Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/reporting.idl b/third_party/blink/web_tests/external/wpt/interfaces/reporting.idl index 05d5a42..f5370e8f 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/reporting.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/reporting.idl
@@ -5,10 +5,12 @@ [Exposed=(Window,Worker)] interface ReportBody { + [Default] object toJSON(); }; [Exposed=(Window,Worker)] interface Report { + [Default] object toJSON(); readonly attribute DOMString type; readonly attribute DOMString url; readonly attribute ReportBody? body; @@ -33,6 +35,7 @@ [Exposed=(Window,Worker)] interface DeprecationReportBody : ReportBody { + [Default] object toJSON(); readonly attribute DOMString id; readonly attribute Date? anticipatedRemoval; readonly attribute DOMString message; @@ -43,6 +46,7 @@ [Exposed=(Window,Worker)] interface InterventionReportBody : ReportBody { + [Default] object toJSON(); readonly attribute DOMString id; readonly attribute DOMString message; readonly attribute DOMString? sourceFile; @@ -52,6 +56,7 @@ [Exposed=(Window,Worker)] interface CrashReportBody : ReportBody { + [Default] object toJSON(); readonly attribute DOMString? reason; };
diff --git a/third_party/blink/web_tests/external/wpt/reporting/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/reporting/idlharness.any-expected.txt index 2852fc58..55b27a0 100644 --- a/third_party/blink/web_tests/external/wpt/reporting/idlharness.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/reporting/idlharness.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 56 tests; 11 PASS, 45 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 61 tests; 11 PASS, 50 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation FAIL ReportBody interface: existence and properties of interface object assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing @@ -8,12 +8,14 @@ FAIL ReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing FAIL ReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing FAIL ReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing +FAIL ReportBody interface: operation toJSON() assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing FAIL Report interface: existence and properties of interface object assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface object length assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface object name assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: existence and properties of interface prototype object assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "Report" expected property "Report" missing +FAIL Report interface: operation toJSON() assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: attribute type assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: attribute url assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: attribute body assert_own_property: self does not have own property "Report" expected property "Report" missing @@ -32,6 +34,7 @@ FAIL DeprecationReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing +FAIL DeprecationReportBody interface: operation toJSON() assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: attribute id assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: attribute anticipatedRemoval assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: attribute message assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing @@ -44,6 +47,7 @@ FAIL InterventionReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing +FAIL InterventionReportBody interface: operation toJSON() assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: attribute id assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: attribute message assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: attribute sourceFile assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing @@ -55,6 +59,7 @@ FAIL CrashReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing FAIL CrashReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing FAIL CrashReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing +FAIL CrashReportBody interface: operation toJSON() assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing FAIL CrashReportBody interface: attribute reason assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/reporting/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/reporting/idlharness.any.worker-expected.txt index 2d07eec..ce631f1 100644 --- a/third_party/blink/web_tests/external/wpt/reporting/idlharness.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/reporting/idlharness.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 56 tests; 2 PASS, 54 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 61 tests; 2 PASS, 59 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation FAIL ReportBody interface: existence and properties of interface object assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing @@ -8,12 +8,14 @@ FAIL ReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing FAIL ReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing FAIL ReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing +FAIL ReportBody interface: operation toJSON() assert_own_property: self does not have own property "ReportBody" expected property "ReportBody" missing FAIL Report interface: existence and properties of interface object assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface object length assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface object name assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: existence and properties of interface prototype object assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "Report" expected property "Report" missing +FAIL Report interface: operation toJSON() assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: attribute type assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: attribute url assert_own_property: self does not have own property "Report" expected property "Report" missing FAIL Report interface: attribute body assert_own_property: self does not have own property "Report" expected property "Report" missing @@ -32,6 +34,7 @@ FAIL DeprecationReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing +FAIL DeprecationReportBody interface: operation toJSON() assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: attribute id assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: attribute anticipatedRemoval assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing FAIL DeprecationReportBody interface: attribute message assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing @@ -44,6 +47,7 @@ FAIL InterventionReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing +FAIL InterventionReportBody interface: operation toJSON() assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: attribute id assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: attribute message assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing FAIL InterventionReportBody interface: attribute sourceFile assert_own_property: self does not have own property "InterventionReportBody" expected property "InterventionReportBody" missing @@ -55,6 +59,7 @@ FAIL CrashReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing FAIL CrashReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing FAIL CrashReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing +FAIL CrashReportBody interface: operation toJSON() assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing FAIL CrashReportBody interface: attribute reason assert_own_property: self does not have own property "CrashReportBody" expected property "CrashReportBody" missing Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js b/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js index 30645fb0..6ef03b3 100644 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js +++ b/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js
@@ -32,7 +32,7 @@ } function toByteArray(data) { - // Convert JS objects to byte array + // Convert JS objects to byte array. let byteArray = new Uint8Array(0); let tmpData = data; @@ -49,7 +49,7 @@ // Compares NDEFRecords that were provided / received by the mock service. // TODO: Use different getters to get received record data, -// see spec changes at https://github.com/w3c/web-nfc/pull/243 +// see spec changes at https://github.com/w3c/web-nfc/pull/243. function compareNDEFRecords(providedRecord, receivedRecord) { assert_equals(providedRecord.recordType, receivedRecord.recordType); @@ -105,7 +105,7 @@ // Checks whether NFCReaderOptions are matched with given message. function matchesWatchOptions(message, options) { - // Filter by Web NFC id + // Filter by Web NFC id. if (!matchesWebNfcId(message.url, options.url)) return false; // Matches any record / media type. @@ -114,7 +114,7 @@ return true; } - // Filter by mediaType and recordType + // Filter by mediaType and recordType. for (let record of message.records) { if (options.mediaType != null && options.mediaType !== "" && options.mediaType !== record.mediaType) { @@ -175,14 +175,15 @@ this.client_ = null; this.watchers_ = []; this.reading_messages_ = []; + this.operations_suspended_ = false; } - // NFC delegate functions + // NFC delegate functions. async push(message, options) { let error = this.getHWError(); if (error) return error; - // Cancel previous pending push operation + // Cancel previous pending push operation. if (this.pending_promise_func_) { this.cancelPendingPushOperation(); } @@ -192,9 +193,12 @@ return new Promise(resolve => { this.pending_promise_func_ = resolve; - if (options.timeout && options.timeout !== Infinity && + // Pend push operation if NFC operation is suspended. + if (this.operations_suspended_) { + // Do nothing, pends push operation. + } else if (options.timeout && options.timeout !== Infinity && !this.push_completed_) { - // Resolve with TimeoutError, else pending push operation. + // Resolve with TimeoutError, else pend push operation. if (this.push_should_timeout_) { resolve( createNFCError(device.mojom.NFCErrorType.TIMER_EXPIRED)); @@ -226,11 +230,14 @@ } this.watchers_.push({id: id, options: options}); - // Triggers onWatch if the new watcher matches existing messages - for (let message of this.reading_messages_) { - if (matchesWatchOptions(message, options)) { - this.client_.onWatch( - [id], fake_tag_serial_number, toMojoNDEFMessage(message)); + // Ignore reading if NFC operation is suspended. + if(!this.operations_suspended_) { + // Triggers onWatch if the new watcher matches existing messages. + for (let message of this.reading_messages_) { + if (matchesWatchOptions(message, options)) { + this.client_.onWatch( + [id], fake_tag_serial_number, toMojoNDEFMessage(message)); + } } } @@ -290,6 +297,7 @@ this.push_completed_ = true; this.watchers_ = []; this.reading_messages_ = []; + this.operations_suspended_ = false; this.cancelPendingPushOperation(); this.bindingSet_.closeAllBindings(); this.interceptor_.stop(); @@ -311,10 +319,12 @@ // Sets message that is used to deliver NFC reading updates. setReadingMessage(message) { this.reading_messages_.push(message); - // Ignore reading if NFCPushOptions.ignoreRead is true + // Ignore reading if NFC operation is suspended. + if(this.operations_suspended_) return; + // Ignore reading if NFCPushOptions.ignoreRead is true. if(this.push_options_ && this.push_options_.ignoreRead) return; - // Triggers onWatch if the new message matches existing watchers + // Triggers onWatch if the new message matches existing watchers. for (let watcher of this.watchers_) { if (matchesWatchOptions(message, watcher.options)) { this.client_.onWatch( @@ -327,6 +337,31 @@ setPushShouldTimeout(result) { this.push_should_timeout_ = result; } + + // Suspends all pending NFC operations. Could be used when web page + // visibility is lost. + suspendNFCOperations() { + this.operations_suspended_ = true; + } + + // Resumes all suspended NFC operations. + resumeNFCOperations() { + this.operations_suspended_ = false; + // Resumes pending NFC reading. + for (let watcher of this.watchers_) { + for (let message of this.reading_messages_) { + if (matchesWatchOptions(message, watcher.options)) { + this.client_.onWatch( + [watcher.id], fake_tag_serial_number, + toMojoNDEFMessage(message)); + } + } + } + // Resumes pending push operation. + if (this.pending_promise_func_) { + this.pending_promise_func_(createNFCError(null)); + } + } } let testInternal = {
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_scan_iframe.https.html b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_scan_iframe.https.html index 1f29fe4b..31e79b0 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_scan_iframe.https.html +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_scan_iframe.https.html
@@ -25,10 +25,13 @@ const iframeLoadWatcher = new EventWatcher(t, iframe, 'load'); document.body.appendChild(iframe); await iframeLoadWatcher.wait_for('load'); - // Focus on iframe + // Focus on iframe. iframe.contentWindow.document.getElementById('foo').focus(); assert_true(iframe.contentDocument.hasFocus(), 'iframe gains the focus'); - + // Suspend NFC operations is async in blink, use setTimeout as a workaround. + // TODO(wanming.lin@intel.com): find a good way to eliminate this race + // condition. + await new Promise(resolve => t.step_timeout(resolve, 0)); mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)])); await promise;
diff --git a/third_party/blink/web_tests/http/tests/permissions/resources/test-query.js b/third_party/blink/web_tests/http/tests/permissions/resources/test-query.js index 0c9eff1..eb2b361 100644 --- a/third_party/blink/web_tests/http/tests/permissions/resources/test-query.js +++ b/third_party/blink/web_tests/http/tests/permissions/resources/test-query.js
@@ -27,7 +27,7 @@ async_test(function(test) { navigator.permissions.query({name:'ambient-light-sensor'}).then(function(result) { assert_true(result instanceof PermissionStatus); - assert_equals(result.state, 'granted'); + assert_equals(result.state, 'denied'); test.done(); }).catch(function() { assert_unreached('querying ambient-light-sensor permission should not fail.') @@ -37,7 +37,7 @@ async_test(function(test) { navigator.permissions.query({name:'accelerometer'}).then(function(result) { assert_true(result instanceof PermissionStatus); - assert_equals(result.state, 'granted'); + assert_equals(result.state, 'denied'); test.done(); }).catch(function() { assert_unreached('querying accelerometer permission should not fail.') @@ -47,7 +47,7 @@ async_test(function(test) { navigator.permissions.query({name:'gyroscope'}).then(function(result) { assert_true(result instanceof PermissionStatus); - assert_equals(result.state, 'granted'); + assert_equals(result.state, 'denied'); test.done(); }).catch(function() { assert_unreached('querying gyroscope permission should not fail.') @@ -57,7 +57,7 @@ async_test(function(test) { navigator.permissions.query({name:'magnetometer'}).then(function(result) { assert_true(result instanceof PermissionStatus); - assert_equals(result.state, 'granted'); + assert_equals(result.state, 'denied'); test.done(); }).catch(function() { assert_unreached('querying magnetometer permission should not fail.') @@ -82,7 +82,7 @@ }).catch(function() { assert_unreached('querying camera permission should not fail.') }); -}, 'Test geolocation permission in ' + get_current_scope() + ' scope.'); +}, 'Test camera permission in ' + get_current_scope() + ' scope.'); async_test(function(test) { navigator.permissions.query({name:'microphone'}).then(function(result) { @@ -92,7 +92,7 @@ }).catch(function() { assert_unreached('querying microphone permission should not fail.') }); -}, 'Test geolocation permission in ' + get_current_scope() + ' scope.'); +}, 'Test microphone permission in ' + get_current_scope() + ' scope.'); async_test(function(test) { navigator.permissions.query({name:'midi'}).then(function(result) {
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index c767408d..ead7975 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1219,6 +1219,9 @@ getter applicationServerKey getter userVisibleOnly method constructor +interface QuicTransport + attribute @@toStringTag + method constructor interface ReadableStream attribute @@toStringTag getter locked
diff --git a/third_party/blink/web_tests/virtual/not-site-per-process/README.md b/third_party/blink/web_tests/virtual/not-site-per-process/README.md index 2c70610a..7da7f6c6 100644 --- a/third_party/blink/web_tests/virtual/not-site-per-process/README.md +++ b/third_party/blink/web_tests/virtual/not-site-per-process/README.md
@@ -15,7 +15,11 @@ Tests under `virtual/not-site-per-process` are run with `--disable-site-isolation-trials` cmdline flag which turns off site isolation. This is needed to preserve test coverage provided by around -60 tests that fail when run with site isolation. +60 tests that fail when run with site isolation. `isolated-code-cache` tests are +also run with `--disable-features=SplitCacheByNetworkIsolationKey` which turns +off HTTP cache partitioning. This is needed as a test expects cross-origin +resources to be cached. Equivalent tests with the feature enabled can be found +under `virtual/split-http-cache-not-site-per-process`. When modifying the list of files that behave differently with and without OOPIFs, please consider modifying all the locations below:
diff --git a/third_party/blink/web_tests/virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/README.txt b/third_party/blink/web_tests/virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/README.txt new file mode 100644 index 0000000..58f5e0e --- /dev/null +++ b/third_party/blink/web_tests/virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/README.txt
@@ -0,0 +1,6 @@ +# This suite runs the tests in http/tests/devtools/isolated-code-cache with +# --enable-features=SplitCacheByNetworkIsolationKey +# --disable-site-isolation-trials +# This feature partitions the HTTP cache by network isolation key for improved +# security. Tracking bug: crbug.com/910708. This test disables site isolation, +# which would cause similar results.
diff --git a/third_party/blink/web_tests/virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/cross-origin-test-expected.txt b/third_party/blink/web_tests/virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/cross-origin-test-expected.txt new file mode 100644 index 0000000..81e758db --- /dev/null +++ b/third_party/blink/web_tests/virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/cross-origin-test-expected.txt
@@ -0,0 +1,82 @@ +Tests V8 code cache for javascript resources + +---First navigation - produce and consume code cache ------ + +v8.compile Properties: +{ + data : { + columnNumber : 0 + lineNumber : 0 + notStreamedReason : "script too small" + streamed : <boolean> + url : .../devtools/resources/v8-cache-script.js + } + endTime : <number> + startTime : <number> + type : "v8.compile" +} +Text details for v8.compile: v8-cache-script.js:1 +v8.compile Properties: +{ + data : { + columnNumber : 0 + lineNumber : 0 + notStreamedReason : "already used streamed data" + streamed : <boolean> + url : .../devtools/resources/v8-cache-script.js + } + endTime : <number> + startTime : <number> + type : "v8.compile" +} +Text details for v8.compile: v8-cache-script.js:1 +v8.compile Properties: +{ + data : { + columnNumber : 0 + lineNumber : 0 + notStreamedReason : "already used streamed data" + producedCacheSize : <number> + streamed : <boolean> + url : .../devtools/resources/v8-cache-script.js + } + endTime : <number> + startTime : <number> + type : "v8.compile" +} +Text details for v8.compile: v8-cache-script.js:1 +v8.compile Properties: +{ + data : { + cacheConsumeOptions : "code" + cacheRejected : false + columnNumber : 0 + consumedCacheSize : <number> + lineNumber : 0 + notStreamedReason : "already used streamed data" + streamed : <boolean> + url : .../devtools/resources/v8-cache-script.js + } + endTime : <number> + startTime : <number> + type : "v8.compile" +} +Text details for v8.compile: v8-cache-script.js:1 + +--- Second navigation - from a different origin ------ + +v8.compile Properties: +{ + data : { + columnNumber : 0 + lineNumber : 0 + notStreamedReason : "script too small" + streamed : <boolean> + url : .../devtools/resources/v8-cache-script.js + } + endTime : <number> + startTime : <number> + type : "v8.compile" +} +Text details for v8.compile: v8-cache-script.js:1 +
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index 3e128bf..aeda26e 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1154,6 +1154,9 @@ [Worker] getter applicationServerKey [Worker] getter userVisibleOnly [Worker] method constructor +[Worker] interface QuicTransport +[Worker] attribute @@toStringTag +[Worker] method constructor [Worker] interface ReadableStream [Worker] attribute @@toStringTag [Worker] getter locked
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index e3b3b80..3b97774 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5965,6 +5965,9 @@ getter applicationServerKey getter userVisibleOnly method constructor +interface QuicTransport + attribute @@toStringTag + method constructor interface RTCCertificate attribute @@toStringTag getter expires
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index 647debe..83990e1 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1136,6 +1136,9 @@ [Worker] getter applicationServerKey [Worker] getter userVisibleOnly [Worker] method constructor +[Worker] interface QuicTransport +[Worker] attribute @@toStringTag +[Worker] method constructor [Worker] interface ReadableStream [Worker] attribute @@toStringTag [Worker] getter locked
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7376eb5..823baa4 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -4740,22 +4740,35 @@ <int value="1" label="By JavaScript"/> </enum> -<enum name="BackForwardCacheEvictedReason"> - <int value="0" label="Timeout"/> - <int value="1" label="Cache limit"/> - <int value="2" label="JavaScript execution"/> - <int value="3" label="Renderer process killed"/> - <int value="4" label="Renderer process crashed"/> - <int value="5" label="Dialog"/> - <int value="6" label="Granted media stream access"/> - <int value="7" label="Scheduler tracked feature used"/> -</enum> - <enum name="BackForwardCacheHistoryNavigationOutcome"> <int value="0" label="Restored"/> <int value="1" label="Not restored"/> </enum> +<enum name="BackForwardCacheNotRestoredReason"> + <int value="0" label="Not main frame. This shouldn't be recorded."/> + <int value="1" label="Back forward cache disabled"/> + <int value="2" label="Related active contents exist"/> + <int value="3" label="HTTP status not OK"/> + <int value="4" label="Scheme not HTTP or HTTPS"/> + <int value="5" label="Loading"/> + <int value="6" label="Was granted media access"/> + <int value="7" label="Blocklisted features"/> + <int value="8" label="Disable for render frame host called"/> + <int value="9" label="Domain not allowed"/> + <int value="10" label="HTTP method not GET"/> + <int value="11" label="Subframe is navigating"/> + <int value="12" label="Timeout"/> + <int value="13" label="Cache limit"/> + <int value="14" label="JavaScript execution"/> + <int value="15" label="Renderer process killed"/> + <int value="16" label="Renderer process crashed"/> + <int value="17" label="Dialog"/> + <int value="18" label="Granted media stream access"/> + <int value="19" label="Scheduler tracked feature used"/> + <int value="20" label="Conflicting BrowsingInstance"/> +</enum> + <enum name="BackForwardNavigationType"> <int value="0" label="Fast back navigation with WKBackForwardList"/> <int value="1" label="Slow back navigation"/> @@ -10130,6 +10143,7 @@ <int value="55" label="System wake lock"/> <int value="56" label="Legacy cookie access"/> <int value="57" label="Native file system write guard"/> + <int value="58" label="Installed web app metadata"/> </enum> <enum name="ContentTypeParseableResult"> @@ -20956,6 +20970,7 @@ <int value="1394" label="AUTOTESTPRIVATE_GETAPPWINDOWLIST"/> <int value="1395" label="AUTOTESTPRIVATE_SETAPPWINDOWSTATE"/> <int value="1396" label="AUTOTESTPRIVATE_CLOSEAPPWINDOW"/> + <int value="1397" label="AUTOTESTPRIVATE_REFRESHENTERPRISEPOLICIES"/> </enum> <enum name="ExtensionIconState"> @@ -32768,6 +32783,12 @@ <int value="5" label="Invalid GUID"/> </enum> +<enum name="InvalidDevicePolicyFilesStatus"> + <int value="0" label="All valid"/> + <int value="1" label="Some invalid"/> + <int value="2" label="All invalid"/> +</enum> + <enum name="InvalidOriginReason"> <int value="0" label="Opaque Origin"/> <int value="1" label="Empty URL"/> @@ -39112,6 +39133,7 @@ <int value="4" label="Password Generation Confirmation"/> <int value="5" label="Profile Chooser"/> <int value="6" label="Passwords Accessory Sheet"/> + <int value="7" label="Touch To Fill"/> </enum> <enum name="ManifestFetchResultType">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 997e61a..5fa17af0 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -13440,17 +13440,17 @@ </summary> </histogram> -<histogram name="BackForwardCache.HistoryNavigationOutcome.EvictedReason" - enum="BackForwardCacheEvictedReason" expires_after="2020-10-01"> +<histogram name="BackForwardCache.HistoryNavigationOutcome.NotRestoredReason" + enum="BackForwardCacheNotRestoredReason" expires_after="2020-10-01"> <owner>bfcache-dev@chromium.org</owner> <owner>hajimehoshi@chromium.org</owner> <summary> - When navigating back to a page in the session history, this records the - reason why the page is evicted from the back-forward cache. Eviction can - happen when the page can no longer be held by the cache. This is a breakdown - metric of BackForwardCache.HistoryNavigationOutcome's 'Evicted' value. + When navigating back to a page in the session history, record why it wasn't + restored from the cache. The page might not have entered the back-forward in + the first place based on the features used, or it might have been evicted + while being in the cache. - Recording starts as of M79. + This recording starts as of M79. </summary> </histogram> @@ -37315,6 +37315,10 @@ <histogram name="Enterprise.InvalidDevicePolicyFiles" units="files" expires_after="2020-07-02"> + <obsolete> + Deprecated 10/2019, since no code reports it anymore. Superseded by + Enterprise.InvalidDevicePolicyFilesStatus. + </obsolete> <owner>emaxx@chromium.org</owner> <owner>igorcov@chromium.org</owner> <summary> @@ -37324,6 +37328,17 @@ </summary> </histogram> +<histogram name="Enterprise.InvalidDevicePolicyFilesStatus" + enum="InvalidDevicePolicyFilesStatus" expires_after="M83"> + <owner>emaxx@chromium.org</owner> + <owner>igorcov@chromium.org</owner> + <owner>vsavu@chromium.org</owner> + <summary> + Chrome OS only. Result of checking if device policy files are valid when + reading the device policy data. + </summary> +</histogram> + <histogram name="Enterprise.IOSPolicies" units="units"> <owner>mnissler@chromium.org</owner> <summary> @@ -80935,6 +80950,42 @@ </summary> </histogram> +<histogram name="Net.QuicSession.HeaderCompressionRatioHpackReceived" units="%" + expires_after="2020-10-08"> + <owner>bnc@chromium.org</owner> + <owner>src/net/quic/OWNERS</owner> + <summary> + Header compression ratio as percentage for received headers using HPACK. + </summary> +</histogram> + +<histogram name="Net.QuicSession.HeaderCompressionRatioHpackSent" units="%" + expires_after="2020-10-08"> + <owner>bnc@chromium.org</owner> + <owner>src/net/quic/OWNERS</owner> + <summary> + Header compression ratio as percentage for sent headers using HPACK. + </summary> +</histogram> + +<histogram name="Net.QuicSession.HeaderCompressionRatioQpackReceived" units="%" + expires_after="2020-10-08"> + <owner>bnc@chromium.org</owner> + <owner>src/net/quic/OWNERS</owner> + <summary> + Header compression ratio as percentage for received headers using QPACK. + </summary> +</histogram> + +<histogram name="Net.QuicSession.HeaderCompressionRatioQpackSent" units="%" + expires_after="2020-10-08"> + <owner>bnc@chromium.org</owner> + <owner>src/net/quic/OWNERS</owner> + <summary> + Header compression ratio as percentage for sent headers using QPACK. + </summary> +</histogram> + <histogram name="Net.QuicSession.HeadersHOLBlockedTime" units="Milliseconds" expires_after="2018-05-09"> <obsolete> @@ -115846,42 +115897,6 @@ </summary> </histogram> -<histogram name="QuicSession.HeaderCompressionRatioHpackReceived" units="%" - expires_after="2020-10-08"> - <owner>bnc@chromium.org</owner> - <owner>src/net/quic/OWNERS</owner> - <summary> - Header compression ratio as percentage for received headers using HPACK. - </summary> -</histogram> - -<histogram name="QuicSession.HeaderCompressionRatioHpackSent" units="%" - expires_after="2020-10-08"> - <owner>bnc@chromium.org</owner> - <owner>src/net/quic/OWNERS</owner> - <summary> - Header compression ratio as percentage for sent headers using HPACK. - </summary> -</histogram> - -<histogram name="QuicSession.HeaderCompressionRatioQpackReceived" units="%" - expires_after="2020-10-08"> - <owner>bnc@chromium.org</owner> - <owner>src/net/quic/OWNERS</owner> - <summary> - Header compression ratio as percentage for received headers using QPACK. - </summary> -</histogram> - -<histogram name="QuicSession.HeaderCompressionRatioQpackSent" units="%" - expires_after="2020-10-08"> - <owner>bnc@chromium.org</owner> - <owner>src/net/quic/OWNERS</owner> - <summary> - Header compression ratio as percentage for sent headers using QPACK. - </summary> -</histogram> - <histogram name="QuicSession.Qpack.HeaderListCountWhenBlockedStreamLimited" units="count" expires_after="2020-10-08"> <owner>bnc@chromium.org</owner>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index da8707e..c52af632 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -630,9 +630,10 @@ 'platform': 'win', 'target_bits': 32, 'dimension': { - 'pool': 'chrome.tests.perf', - 'os': 'Windows-2008ServerR2-SP1', - 'gpu': '102b:0532' + 'gpu': '102b:0532-6.1.7600.16385', + 'os': 'Windows-2008ServerR2-SP1', + 'pool': 'chrome.tests.perf', + 'synthetic_product_name': 'PowerEdge R210 II (Dell Inc.)', }, }, 'Win 7 Nvidia GPU Perf': {
diff --git a/tools/perf/core/results_processor/command_line.py b/tools/perf/core/results_processor/command_line.py index 5a6ece3..e5c51fb 100644 --- a/tools/perf/core/results_processor/command_line.py +++ b/tools/perf/core/results_processor/command_line.py
@@ -20,7 +20,7 @@ # These formats are always handled natively, and never handed over to Telemetry. -HANDLED_NATIVELY = ['none', 'json-test-results'] +HANDLED_NATIVELY = ['none', 'json-test-results', 'histograms', 'html', 'csv'] def ArgumentParser(standalone=False, legacy_formats=None): @@ -131,25 +131,11 @@ else: chosen_formats = ['html'] - # The following is a temporary hack to switch on native handling of output - # formats for several benchmarks. This is an experiment to make sure - # that Results Processor is ready to handle output on all platforms. - # TODO(crbug.com/981349): Remove this after experiment is finished (i.e. - # all formats are considered HANDLED_NATIVELY). - force_native = False - if 'positional_args' in options.__dict__ and options.positional_args: - benchmark_name = options.positional_args[0] - if benchmark_name in ['power.desktop', 'startup.mobile', 'jetstream2', - 'octane', 'blink_perf.css']: - force_native = True - logging.warning('Force native handling of output formats for %s', - benchmark_name) - options.output_formats = [] for output_format in chosen_formats: if output_format == 'none': continue - elif standalone or output_format in HANDLED_NATIVELY or force_native: + elif standalone or output_format in HANDLED_NATIVELY: options.output_formats.append(output_format) else: options.legacy_output_formats.append(output_format)
diff --git a/tools/perf/core/results_processor/command_line_unittest.py b/tools/perf/core/results_processor/command_line_unittest.py index f67154c..5bf0ac1 100644 --- a/tools/perf/core/results_processor/command_line_unittest.py +++ b/tools/perf/core/results_processor/command_line_unittest.py
@@ -124,10 +124,9 @@ self.assertEqual(options.upload_bucket, 'some-special-bucket') def testDefaultOutputFormat(self): - self.legacy_formats = ['html'] options = self.ParseArgs([]) - self.assertEqual(options.output_formats, []) - self.assertEqual(options.legacy_output_formats, ['html']) + self.assertEqual(options.output_formats, ['html']) + self.assertEqual(options.legacy_output_formats, []) def testUnkownOutputFormatRaises(self): with self.assertRaises(SystemExit):
diff --git a/ui/base/models/menu_model.h b/ui/base/models/menu_model.h index 5bcc620..b0ae539 100644 --- a/ui/base/models/menu_model.h +++ b/ui/base/models/menu_model.h
@@ -39,8 +39,6 @@ TYPE_HIGHLIGHTED, // Performs an action when selected, and has a different // colored background. When placed at the bottom, the // background matches the menu's rounded corners. - TYPE_TITLE, // Plain text that does not perform any action when - // selected. }; MenuModel();
diff --git a/ui/base/models/simple_menu_model.cc b/ui/base/models/simple_menu_model.cc index aa1c2f05..0aeeb3e 100644 --- a/ui/base/models/simple_menu_model.cc +++ b/ui/base/models/simple_menu_model.cc
@@ -17,10 +17,6 @@ const int kSeparatorId = -1; -// Text items are rendered as enabled but are non-interactive with no actions -// and cannot be highlighted. -const int kTitleId = -2; - //////////////////////////////////////////////////////////////////////////////// // SimpleMenuModel::Delegate, public: @@ -146,10 +142,6 @@ AppendItem(std::move(item)); } -void SimpleMenuModel::AddTitle(const base::string16& label) { - AppendItem(Item(kTitleId, TYPE_TITLE, label)); -} - void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type) { if (items_.empty()) { if (separator_type == NORMAL_SEPARATOR) { @@ -468,9 +460,6 @@ bool SimpleMenuModel::IsEnabledAt(int index) const { int command_id = GetCommandIdAt(index); - if (command_id == kTitleId) - return false; - if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index)) return items_[ValidateItemIndex(index)].enabled; @@ -480,8 +469,7 @@ bool SimpleMenuModel::IsVisibleAt(int index) const { int command_id = GetCommandIdAt(index); - if (!delegate_ || command_id == kSeparatorId || command_id == kTitleId || - GetButtonMenuItemAt(index)) + if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index)) return items_[ValidateItemIndex(index)].visible; return delegate_->IsCommandIdVisible(command_id) &&
diff --git a/ui/base/models/simple_menu_model.h b/ui/base/models/simple_menu_model.h index e51bcb4..3cc9d68 100644 --- a/ui/base/models/simple_menu_model.h +++ b/ui/base/models/simple_menu_model.h
@@ -107,7 +107,6 @@ void AddHighlightedItemWithIcon(int command_id, const base::string16& label, const gfx::ImageSkia& icon); - void AddTitle(const base::string16& label); // Adds a separator of the specified type to the model. // - Adding a separator after another separator is always invalid if they
diff --git a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js index a6428db7..ca6debc 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js +++ b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
@@ -10,7 +10,71 @@ '<xf-display-panel id="test-xf-display-panel"></xf-display-panel>'; } -async function testFilesDisplayPanel(done) { +async function testDisplayPanelAttachPanel(done) { + // Get the host display panel container element. + /** @type {!DisplayPanel|!Element} */ + const displayPanel = assert(document.querySelector('#test-xf-display-panel')); + + // Test create/attach/remove sequences. + // Create a progress panel item. + let progressPanel = displayPanel.createPanelItem('testpanel'); + progressPanel.panelType = progressPanel.panelTypeProgress; + + // Attach the panel to it's host display panel. + displayPanel.attachPanelItem(progressPanel); + + // Verify the panel is attached to the document. + assertTrue(!!progressPanel.isConnected); + + // Remove the panel item. + displayPanel.removePanelItem(progressPanel); + + // Verify the panel item is not attached to the document. + assertFalse(progressPanel.isConnected); + + // Create a progress panel item. + progressPanel = displayPanel.createPanelItem('testpanel2'); + progressPanel.panelType = progressPanel.panelTypeProgress; + + // Remove the panel item. + displayPanel.removePanelItem(progressPanel); + + // Try to attach the removed panel to it's host display panel. + displayPanel.attachPanelItem(progressPanel); + + // Verify the panel is not attached to the document. + assertFalse(progressPanel.isConnected); + + done(); +} + +async function testDisplayPanelChangingPanelTypes(done) { + // Get the host display panel container element. + /** @type {!DisplayPanel|!Element} */ + const displayPanel = assert(document.querySelector('#test-xf-display-panel')); + const panelItem = displayPanel.addPanelItem('testpanel'); + panelItem.panelType = panelItem.panelTypeProgress; + + // Verify the panel item indicator is progress. + assertTrue( + panelItem.indicator === 'progress', + 'Wrong panel indicator, got ' + panelItem.indicator); + + // Change the panel item to an error panel. + panelItem.panelType = panelItem.panelTypeError; + + // Verify the panel item indicator is set to error. + assertTrue( + panelItem.indicator === 'status', + 'Wrong panel indicator, got ' + panelItem.indicator); + assertTrue( + panelItem.status === 'failure', + 'Wrong panel status, got ' + panelItem.status); + + done(); +} + +async function testFilesDisplayPanelSummaryPanel(done) { // Get the host display panel container element. /** @type {!DisplayPanel|!Element} */ const displayPanel = assert(document.querySelector('#test-xf-display-panel')); @@ -68,28 +132,5 @@ summaryPanelItem = summaryContainer.querySelector('xf-panel-item'); assertTrue(summaryPanelItem.panelType === summaryPanelItem.panelTypeSummary); - // Test create/attach/remove sequences. - // Create a progress panel item. - progressPanel = displayPanel.createPanelItem('testpanel2'); - progressPanel.panelType = progressPanel.panelTypeProgress; - // Attach the panel to it's host display panel. - displayPanel.attachPanelItem(progressPanel); - // Verify the panel is attached to the document. - assertTrue(!!progressPanel.parentNode); - // Remove the panel item. - displayPanel.removePanelItem(progressPanel); - // Verify the panel item is not attached to the document. - assertTrue(progressPanel.parentNode === null); - - // Create a progress panel item. - progressPanel = displayPanel.createPanelItem('testpanel3'); - progressPanel.panelType = progressPanel.panelTypeProgress; - // Remove the panel item. - displayPanel.removePanelItem(progressPanel); - // Try to attach the removed panel to it's host display panel. - displayPanel.attachPanelItem(progressPanel); - // Verify the panel is not attached to the document. - assertTrue(progressPanel.parentNode === null); - done(); }
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js index 779a1ea..0c0b9a88 100644 --- a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js +++ b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
@@ -445,6 +445,13 @@ } /** + * Getter for the progress indicator. + */ + get indicator() { + return this.getAttribute('indicator'); + } + + /** * Setter to set the success/failure indication. * @param {string} status Status value being set. */ @@ -453,6 +460,13 @@ } /** + * Getter for the success/failure indication. + */ + get status() { + return this.getAttribute('status'); + } + + /** * Setter to set the progress property, sent to any child indicator. * @param {string} progress Progress value being set. * @public
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index 2b2eac6..93bb5833 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -126,14 +126,6 @@ Object.freeze(DirectoryItemTreeBaseMethods); -const TREE_ITEM_INNER_HTML = '<div class="tree-row">' + - ' <paper-ripple fit class="recenteringTouch"></paper-ripple>' + - ' <span class="expand-icon"></span>' + - ' <span class="icon"></span>' + - ' <span class="label entry-name"></span>' + - '</div>' + - '<div class="tree-children" role="group"></div>'; - //////////////////////////////////////////////////////////////////////////////// // TreeItem @@ -223,7 +215,7 @@ * @override */ get labelElement() { - return this.firstElementChild.querySelector('.label'); + return this.rowElement.querySelector('.label'); } } @@ -274,7 +266,6 @@ this.onMetadataUpdateBound_ = undefined; } - /** * The DirectoryEntry corresponding to this DirectoryItem. This may be * a dummy DirectoryEntry. @@ -854,8 +845,6 @@ /** * The DirectoryEntry corresponding to this DirectoryItem. - * @type {DirectoryEntry} - * @override */ get entry() { return this.dirEntry_; @@ -863,7 +852,6 @@ /** * Sets the DirectoryEntry corresponding to this DirectoryItem. - * @param {DirectoryEntry} value The directory entry. */ set entry(value) { this.dirEntry_ = value; @@ -1522,26 +1510,23 @@ * A TreeItem which represents a shortcut for Drive folder. * Shortcut items are displayed as top-level children of DirectoryTree. */ -class ShortcutItem extends cr.ui.TreeItem { +class ShortcutItem extends TreeItem { /** * @param {!NavigationModelShortcutItem} modelItem NavigationModelItem of this * volume. * @param {!DirectoryTree} tree Current tree, which contains this item. */ constructor(modelItem, tree) { - super(); - // Get the original label id defined by TreeItem, before overwriting - // prototype. - const labelId = this.labelElement.id; + super(modelItem.entry.name, tree); this.__proto__ = ShortcutItem.prototype; - this.parentTree_ = tree; + if (window.IN_TEST) { + this.setAttribute('dir-type', 'ShortcutItem'); + } + this.dirEntry_ = modelItem.entry; this.modelItem_ = modelItem; - this.innerHTML = TREE_ITEM_INNER_HTML; - this.labelElement.id = labelId; - const icon = this.querySelector('.icon'); icon.classList.add('item-icon'); icon.setAttribute('volume-type-icon', 'shortcut'); @@ -1549,13 +1534,6 @@ if (tree.contextMenuForRootItems) { this.setContextMenu_(tree.contextMenuForRootItems); } - - this.label = modelItem.entry.name; - - if (window.IN_TEST) { - this.setAttribute('dir-type', 'ShortcutItem'); - this.setAttribute('entry-label', this.label); - } } /** @@ -1637,18 +1615,21 @@ }); } + /** + * The DirectoryEntry corresponding to this DirectoryItem. + */ get entry() { return this.dirEntry_; } + + /** + * @type {!NavigationModelVolumeItem} + */ get modelItem() { return this.modelItem_; } - get labelElement() { - return this.firstElementChild.querySelector('.label'); - } } - //////////////////////////////////////////////////////////////////////////////// // AndroidAppItem @@ -1656,38 +1637,30 @@ * A TreeItem representing an Android picker app. These Android app items are * shown as top-level volume entries of the DirectoryTree. */ -class AndroidAppItem extends cr.ui.TreeItem { +class AndroidAppItem extends TreeItem { /** * @param {!NavigationModelAndroidAppItem} modelItem NavigationModelItem * associated with this volume. * @param {!DirectoryTree} tree Directory tree. */ constructor(modelItem, tree) { - super(); - // Get the original label id defined by TreeItem, before overwriting - // prototype. - const labelId = this.labelElement.id; + super(modelItem.androidApp.name, tree); this.__proto__ = AndroidAppItem.prototype; - /** @private {!DirectoryTree} */ - this.parentTree_ = tree; + if (window.IN_TEST) { + this.setAttribute('dir-type', 'AndroidAppItem'); + } - /** @private {!NavigationModelAndroidAppItem} */ this.modelItem_ = modelItem; - this.innerHTML = TREE_ITEM_INNER_HTML; - this.labelElement.id = labelId; + const icon = this.querySelector('.icon'); + icon.classList.add('item-icon'); - /** @public {string} */ - this.label = modelItem.androidApp.name; - - const appIcon = this.querySelector('.icon'); - appIcon.classList.add('item-icon'); if (modelItem.androidApp.iconSet) { const backgroundImage = util.iconSetToCSSBackgroundImageValue(modelItem.androidApp.iconSet); if (backgroundImage !== 'none') { - appIcon.setAttribute('style', 'background-image: ' + backgroundImage); + icon.setAttribute('style', 'background-image: ' + backgroundImage); } } @@ -1727,40 +1700,32 @@ /** * FakeItem is used by Recent and Linux files. */ -class FakeItem extends cr.ui.TreeItem { +class FakeItem extends TreeItem { /** * @param {!VolumeManagerCommon.RootType} rootType root type. * @param {!NavigationModelFakeItem} modelItem * @param {!DirectoryTree} tree Current tree, which contains this item. */ constructor(rootType, modelItem, tree) { - super(); - // Get the original label id defined by TreeItem, before overwriting - // prototype. - const labelId = this.labelElement.id; + super(modelItem.label, tree); this.__proto__ = FakeItem.prototype; if (window.IN_TEST) { this.setAttribute('dir-type', 'FakeItem'); - this.setAttribute('entry-label', modelItem.label); } - this.rootType_ = rootType; - this.parentTree_ = tree; - this.modelItem_ = modelItem; - this.dirEntry_ = modelItem.entry; - this.innerHTML = TREE_ITEM_INNER_HTML; - this.labelElement.id = labelId; - this.label = modelItem.label; this.directoryModel_ = tree.directoryModel; + this.dirEntry_ = modelItem.entry; + this.modelItem_ = modelItem; + this.rootType_ = rootType; + + const icon = this.querySelector('.icon'); + icon.classList.add('item-icon'); + icon.setAttribute('root-type-icon', rootType); if (tree.disabledContextMenu) { cr.ui.contextMenuHandler.setContextMenu(this, tree.disabledContextMenu); } - - const icon = queryRequiredElement('.icon', this); - icon.classList.add('item-icon'); - icon.setAttribute('root-type-icon', rootType); } /** @@ -1806,19 +1771,23 @@ } /** - * FakeItem doesn't really have shared status/icon so we define here as no-op. + * FakeItem's do not have shared status/icon. */ updateDriveSpecificIcons() {} + /** + * The DirectoryEntry corresponding to this DirectoryItem. + */ get entry() { return this.dirEntry_; } + + /** + * @type {!NavigationModelVolumeItem} + */ get modelItem() { return this.modelItem_; } - get labelElement() { - return this.firstElementChild.querySelector('.label'); - } } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc index f58099f2..0fcca1e 100644 --- a/ui/views/controls/menu/menu_item_view.cc +++ b/ui/views/controls/menu/menu_item_view.cc
@@ -200,7 +200,6 @@ node_data->SetCheckedState(is_checked ? ax::mojom::CheckedState::kTrue : ax::mojom::CheckedState::kFalse); } break; - case TITLE: case NORMAL: case SEPARATOR: case EMPTY: @@ -1140,9 +1139,7 @@ : style::CONTEXT_MENU; style::TextStyle text_style = style::STYLE_PRIMARY; - if (type_ == Type::TITLE) - text_style = style::STYLE_PRIMARY; - else if (type_ == HIGHLIGHTED) + if (type_ == HIGHLIGHTED) text_style = style::STYLE_HIGHLIGHTED; else if (!GetEnabled()) text_style = style::STYLE_DISABLED;
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h index 481075d..e129bed9 100644 --- a/ui/views/controls/menu/menu_item_view.h +++ b/ui/views/controls/menu/menu_item_view.h
@@ -95,9 +95,8 @@ HIGHLIGHTED, // Performs an action when selected, and has a // different colored background that merges with the // menu's rounded corners when placed at the bottom. - TITLE, // Title text, does not perform any action. - EMPTY, // EMPTY is a special type for empty menus that is only - // used internally. + EMPTY, // EMPTY is a special type for empty menus that is only used + // internally. }; // Where the menu should be drawn, above or below the bounds (when
diff --git a/ui/views/controls/menu/menu_model_adapter.cc b/ui/views/controls/menu/menu_model_adapter.cc index 6128da1..09b72733 100644 --- a/ui/views/controls/menu/menu_model_adapter.cc +++ b/ui/views/controls/menu/menu_model_adapter.cc
@@ -70,9 +70,6 @@ base::Optional<MenuItemView::Type> type; ui::MenuModel::ItemType menu_type = model->GetTypeAt(model_index); switch (menu_type) { - case ui::MenuModel::TYPE_TITLE: - type = MenuItemView::TITLE; - break; case ui::MenuModel::TYPE_COMMAND: case ui::MenuModel::TYPE_BUTTON_ITEM: type = MenuItemView::NORMAL;
diff --git a/ui/views/controls/menu/menu_model_adapter_unittest.cc b/ui/views/controls/menu/menu_model_adapter_unittest.cc index 17ce9a0..d48ec3d 100644 --- a/ui/views/controls/menu/menu_model_adapter_unittest.cc +++ b/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -213,9 +213,6 @@ // Check type. switch (model_item.type) { - case ui::MenuModel::TYPE_TITLE: - EXPECT_EQ(views::MenuItemView::TITLE, item->GetType()); - break; case ui::MenuModel::TYPE_COMMAND: EXPECT_EQ(views::MenuItemView::NORMAL, item->GetType()); break; @@ -290,9 +287,6 @@ // Check type. switch (model_item.type) { - case ui::MenuModel::TYPE_TITLE: - EXPECT_EQ(views::MenuItemView::TITLE, item->GetType()); - break; case ui::MenuModel::TYPE_COMMAND: EXPECT_EQ(views::MenuItemView::NORMAL, item->GetType()); break;
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn index 284d1bc8..68e8f369 100644 --- a/weblayer/BUILD.gn +++ b/weblayer/BUILD.gn
@@ -67,6 +67,8 @@ "public/navigation_controller.h", "public/navigation_observer.h", "public/profile.h", + "utility/content_utility_client_impl.cc", + "utility/content_utility_client_impl.h", ] configs += [ @@ -91,6 +93,7 @@ "//content/public/child", "//content/public/common", "//content/public/common:service_names", + "//content/public/utility", "//net", "//net:net_resources", "//sandbox",
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc index 287761e..70f804f 100644 --- a/weblayer/app/content_main_delegate_impl.cc +++ b/weblayer/app/content_main_delegate_impl.cc
@@ -20,6 +20,7 @@ #include "ui/base/ui_base_paths.h" #include "weblayer/browser/content_browser_client_impl.h" #include "weblayer/common/content_client_impl.h" +#include "weblayer/utility/content_utility_client_impl.h" #if defined(OS_ANDROID) #include "base/android/apk_assets.h" @@ -181,4 +182,10 @@ return browser_client_.get(); } +content::ContentUtilityClient* +ContentMainDelegateImpl::CreateContentUtilityClient() { + utility_client_ = std::make_unique<ContentUtilityClientImpl>(); + return utility_client_.get(); +} + } // namespace weblayer
diff --git a/weblayer/app/content_main_delegate_impl.h b/weblayer/app/content_main_delegate_impl.h index 9db9f4a..31ea1cb 100644 --- a/weblayer/app/content_main_delegate_impl.h +++ b/weblayer/app/content_main_delegate_impl.h
@@ -16,6 +16,7 @@ namespace weblayer { class ContentClientImpl; class ContentBrowserClientImpl; +class ContentUtilityClientImpl; class ContentMainDelegateImpl : public content::ContentMainDelegate { public: @@ -29,12 +30,14 @@ const std::string& process_type, const content::MainFunctionParams& main_function_params) override; content::ContentBrowserClient* CreateContentBrowserClient() override; + content::ContentUtilityClient* CreateContentUtilityClient() override; private: void InitializeResourceBundle(); MainParams params_; std::unique_ptr<ContentBrowserClientImpl> browser_client_; + std::unique_ptr<ContentUtilityClientImpl> utility_client_; std::unique_ptr<ContentClientImpl> content_client_; DISALLOW_COPY_AND_ASSIGN(ContentMainDelegateImpl);
diff --git a/weblayer/test/BUILD.gn b/weblayer/test/BUILD.gn index e2d8a093..824c690 100644 --- a/weblayer/test/BUILD.gn +++ b/weblayer/test/BUILD.gn
@@ -85,6 +85,7 @@ sources = [ "browsertests_main.cc", + "ssl_browsertest.cc", "test_launcher_delegate_impl.cc", "test_launcher_delegate_impl.h", "weblayer_browser_test.cc",
diff --git a/weblayer/test/DEPS b/weblayer/test/DEPS index f619579..5b71f4a 100644 --- a/weblayer/test/DEPS +++ b/weblayer/test/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+content/public/common", "+content/public/test", "+net/test", ]
diff --git a/weblayer/test/browsertests_main.cc b/weblayer/test/browsertests_main.cc index c0dae98..cb6921c 100644 --- a/weblayer/test/browsertests_main.cc +++ b/weblayer/test/browsertests_main.cc
@@ -4,12 +4,33 @@ #include "base/command_line.h" #include "base/test/launcher/test_launcher.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/network_service_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #include "weblayer/test/test_launcher_delegate_impl.h" +#include "weblayer/utility/content_utility_client_impl.h" int main(int argc, char** argv) { base::CommandLine::Init(argc, argv); size_t parallel_jobs = base::NumParallelJobs(); + + // Set up a working test environment for the network service in case it's + // used. Only create this object in the utility process, so that its members + // don't interfere with other test objects in the browser process. + std::unique_ptr<content::NetworkServiceTestHelper> + network_service_test_helper; + if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kProcessType) == switches::kUtilityProcess) { + network_service_test_helper = + std::make_unique<content::NetworkServiceTestHelper>(); + weblayer::ContentUtilityClientImpl:: + SetNetworkBinderCreationCallbackForTests(base::BindRepeating( + [](content::NetworkServiceTestHelper* helper, + service_manager::BinderRegistry* registry) { + helper->RegisterNetworkBinders(registry); + }, + network_service_test_helper.get())); + } weblayer::TestLauncherDelegateImpl launcher_delegate; return content::LaunchTests(&launcher_delegate, parallel_jobs, argc, argv); }
diff --git a/weblayer/test/ssl_browsertest.cc b/weblayer/test/ssl_browsertest.cc new file mode 100644 index 0000000..191e662 --- /dev/null +++ b/weblayer/test/ssl_browsertest.cc
@@ -0,0 +1,45 @@ +// Copyright 2019 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 "weblayer/test/weblayer_browser_test.h" + +#include "base/files/file_path.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "weblayer/test/weblayer_browser_test_utils.h" + +namespace weblayer { + +IN_PROC_BROWSER_TEST_F(WebLayerBrowserTest, Https) { + net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_server.AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); + + net::EmbeddedTestServer https_server_mismatched( + net::EmbeddedTestServer::TYPE_HTTPS); + https_server_mismatched.SetSSLConfig( + net::EmbeddedTestServer::CERT_MISMATCHED_NAME); + https_server_mismatched.AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); + + ASSERT_TRUE(https_server.Start()); + ASSERT_TRUE(https_server_mismatched.Start()); + + // First navigate to an OK page. + GURL initial_url = https_server.GetURL("/simple_page.html"); + ASSERT_EQ("127.0.0.1", initial_url.host()); + + NavigateAndWaitForCompletion(initial_url, shell()); + + // Now do a navigation that should result in an SSL error. + GURL url_with_mismatched_cert = + https_server_mismatched.GetURL("/simple_page.html"); + + NavigateAndWaitForFailure(url_with_mismatched_cert, shell()); + + // TODO(blundell): Adapt the testing of the interstitial appearing from + // //chrome's ssl_browsertest.cc:(1462-1465) once the interstitial + // functionality is brought up. +} + +} // namespace weblayer
diff --git a/weblayer/test/weblayer_browser_test_test.cc b/weblayer/test/weblayer_browser_test_test.cc index 417dda7e..242e321 100644 --- a/weblayer/test/weblayer_browser_test_test.cc +++ b/weblayer/test/weblayer_browser_test_test.cc
@@ -13,7 +13,7 @@ ASSERT_TRUE(embedded_test_server()->Start()); GURL url = embedded_test_server()->GetURL("/simple_page.html"); - NavigateAndWait(url, shell()); + NavigateAndWaitForCompletion(url, shell()); } } // namespace weblayer
diff --git a/weblayer/test/weblayer_browser_test_utils.cc b/weblayer/test/weblayer_browser_test_utils.cc index a6754b3..28b6437 100644 --- a/weblayer/test/weblayer_browser_test_utils.cc +++ b/weblayer/test/weblayer_browser_test_utils.cc
@@ -19,11 +19,15 @@ // Runs |closure| once |url| is successfully navigated to. class TestNavigationObserver : public NavigationObserver { public: + enum class NavigationEventToObserve { Completion, Failure }; + TestNavigationObserver(base::OnceClosure closure, const GURL& url, + NavigationEventToObserve event, Shell* shell) : closure_(std::move(closure)), url_(url), + event_(event), browser_(shell->browser_controller()) { browser_->GetNavigationController()->AddObserver(this); } @@ -35,23 +39,47 @@ private: // NavigationObserver implementation: void NavigationCompleted(Navigation* navigation) override { - if (navigation->GetURL() == url_) + if (navigation->GetURL() == url_ && + event_ == NavigationEventToObserve::Completion) std::move(closure_).Run(); } + void NavigationFailed(Navigation* navigation) override { + if (navigation->GetURL() == url_ && + event_ == NavigationEventToObserve::Failure) { + std::move(closure_).Run(); + } + } + base::OnceClosure closure_; const GURL url_; + NavigationEventToObserve event_; BrowserController* browser_; }; -} // namespace - -void NavigateAndWait(const GURL& url, Shell* shell) { +// Navigates to |url| in |shell| and waits for |event| to occur. +void NavigateAndWaitForEvent( + const GURL& url, + Shell* shell, + TestNavigationObserver::NavigationEventToObserve event) { base::RunLoop run_loop; - TestNavigationObserver test_observer(run_loop.QuitClosure(), url, shell); + TestNavigationObserver test_observer(run_loop.QuitClosure(), url, event, + shell); shell->browser_controller()->GetNavigationController()->Navigate(url); run_loop.Run(); } +} // namespace + +void NavigateAndWaitForCompletion(const GURL& url, Shell* shell) { + NavigateAndWaitForEvent( + url, shell, TestNavigationObserver::NavigationEventToObserve::Completion); +} + +void NavigateAndWaitForFailure(const GURL& url, Shell* shell) { + NavigateAndWaitForEvent( + url, shell, TestNavigationObserver::NavigationEventToObserve::Failure); +} + } // namespace weblayer
diff --git a/weblayer/test/weblayer_browser_test_utils.h b/weblayer/test/weblayer_browser_test_utils.h index 65daf4ca..d87a1380 100644 --- a/weblayer/test/weblayer_browser_test_utils.h +++ b/weblayer/test/weblayer_browser_test_utils.h
@@ -10,8 +10,11 @@ namespace weblayer { class Shell; -// Navigates |shell| to |url| and wait for successful navigation. -void NavigateAndWait(const GURL& url, Shell* shell); +// Navigates |shell| to |url| and wait for completed navigation. +void NavigateAndWaitForCompletion(const GURL& url, Shell* shell); + +// Navigates |shell| to |url| and wait for failed navigation. +void NavigateAndWaitForFailure(const GURL& url, Shell* shell); } // namespace weblayer
diff --git a/weblayer/utility/DEPS b/weblayer/utility/DEPS new file mode 100644 index 0000000..8ad521e --- /dev/null +++ b/weblayer/utility/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+content/public/utility", +]
diff --git a/weblayer/utility/content_utility_client_impl.cc b/weblayer/utility/content_utility_client_impl.cc new file mode 100644 index 0000000..d9d648e --- /dev/null +++ b/weblayer/utility/content_utility_client_impl.cc
@@ -0,0 +1,36 @@ +// Copyright 2019 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 "weblayer/utility/content_utility_client_impl.h" + +#include "base/bind.h" +#include "base/lazy_instance.h" +#include "base/no_destructor.h" + +namespace weblayer { + +namespace { + +base::LazyInstance<ContentUtilityClientImpl::NetworkBinderCreationCallback>:: + Leaky g_network_binder_creation_callback = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// static +void ContentUtilityClientImpl::SetNetworkBinderCreationCallbackForTests( + NetworkBinderCreationCallback callback) { + g_network_binder_creation_callback.Get() = std::move(callback); +} + +ContentUtilityClientImpl::ContentUtilityClientImpl() {} + +ContentUtilityClientImpl::~ContentUtilityClientImpl() = default; + +void ContentUtilityClientImpl::RegisterNetworkBinders( + service_manager::BinderRegistry* registry) { + if (g_network_binder_creation_callback.Get()) + g_network_binder_creation_callback.Get().Run(registry); +} + +} // namespace weblayer
diff --git a/weblayer/utility/content_utility_client_impl.h b/weblayer/utility/content_utility_client_impl.h new file mode 100644 index 0000000..798edd4 --- /dev/null +++ b/weblayer/utility/content_utility_client_impl.h
@@ -0,0 +1,36 @@ +// Copyright 2019 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 WEBLAYER_UTILITY_CONTENT_UTILITY_CLIENT_IMPL_H_ +#define WEBLAYER_UTILITY_CONTENT_UTILITY_CLIENT_IMPL_H_ + +#include <string> + +#include "base/callback.h" +#include "content/public/utility/content_utility_client.h" + +namespace weblayer { + +class ContentUtilityClientImpl : public content::ContentUtilityClient { + public: + using NetworkBinderCreationCallback = + base::RepeatingCallback<void(service_manager::BinderRegistry*)>; + + static void SetNetworkBinderCreationCallbackForTests( + NetworkBinderCreationCallback callback); + + ContentUtilityClientImpl(); + ~ContentUtilityClientImpl() override; + + // content::ContentUtilityClient: + void RegisterNetworkBinders( + service_manager::BinderRegistry* registry) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ContentUtilityClientImpl); +}; + +} // namespace weblayer + +#endif // WEBLAYER_UTILITY_CONTENT_UTILITY_CLIENT_IMPL_H_