diff --git a/DEPS b/DEPS index 052a34a..6b9cec0 100644 --- a/DEPS +++ b/DEPS
@@ -253,19 +253,19 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '2a04ac3ee1d1a821f0811e9ff1ad75740df8d860', + 'skia_revision': 'f379b259a55e61e4ca173bf392c43ec20ca9e0e4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '31599da502bde251a1556e974da3389cc8512d69', + 'v8_revision': '9e5ad1e99a34694669f2dee0f2fb8901f00760ba', # 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': '152616eedcfded69cab516e093efd3a98190fa5b', + 'angle_revision': '9d486a85e8888ad22a39bf1bb5d15fba90c944cc', # 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': '9c16e141823e93c2d6ad05b94165cc18ffda6ffe', + 'swiftshader_revision': '626c44cc5cf29a877205150149cb66cc074d93b7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -328,7 +328,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '029869e0a26da4dd6442712c2be386aeaeb9492b', + 'devtools_frontend_revision': '393a4054354f1a9c6bdf55b4c44e99ef14467527', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -735,7 +735,7 @@ }, 'src/ios/third_party/earl_grey2/src': { - 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'c5f2de81d09f3a0507335cefe65688ef8fff9a67', + 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'd1d9015293e9414cef561f3d28725a8400d0743f', 'condition': 'checkout_ios', }, @@ -1132,7 +1132,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '52d64c5ec3081ce75f4979eeb9ddd3a232f419cb', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ba94bbeaa857d50798437275242ec7cb72cca7b1', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1730,10 +1730,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'cf04aebdf9b53bb2853f22a81465688daf879ec6', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3486401d1eb80ce4f2fe4b9ad8cc206ad6de4a1e', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'aa5ba0a0f5e55a8715a629bd1d3110a671107a1e', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '117596b15ff93fb5bb1fd8fce457761ead7c3b0f', + Var('webrtc_git') + '/src.git' + '@' + '00112748e187c16693363ec157e42a7738312128', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1803,7 +1803,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@87ec76f30c82ec3864faec1a8408437eeee5782d', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ce66871b870909680af5f991bfffee8cf5ac1686', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index dd83e61..3443e7e 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -286,6 +286,9 @@ Flag.baseFeature(BlinkFeatures.UACH_OVERRIDE_BLANK, "Changes behavior of User-Agent Client Hints to send blank headers " + "when the User-Agent string is overriden"), + Flag.baseFeature(BlinkFeatures.MAX_UNTHROTTLED_TIMEOUT_NESTING_LEVEL, + "Increases the nesting threshold before which " + + "setTimeout(..., <4ms) starts being clamped to 4 ms."), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/android_webview/ui/aw_strings.grd b/android_webview/ui/aw_strings.grd index 4a09324..d92cc5a9 100644 --- a/android_webview/ui/aw_strings.grd +++ b/android_webview/ui/aw_strings.grd
@@ -15,6 +15,7 @@ <output filename="aw_strings_bs.pak" type="data_package" lang="bs" /> <output filename="aw_strings_ca.pak" type="data_package" lang="ca" /> <output filename="aw_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="aw_strings_cy.pak" type="data_package" lang="cy" /> <output filename="aw_strings_da.pak" type="data_package" lang="da" /> <output filename="aw_strings_de.pak" type="data_package" lang="de" /> <output filename="aw_strings_el.pak" type="data_package" lang="el" />
diff --git a/ash/app_list/views/assistant/assistant_dialog_plate.cc b/ash/app_list/views/assistant/assistant_dialog_plate.cc index a146efc..31d1f9f 100644 --- a/ash/app_list/views/assistant/assistant_dialog_plate.cc +++ b/ash/app_list/views/assistant/assistant_dialog_plate.cc
@@ -24,6 +24,7 @@ #include "base/bind.h" #include "base/strings/utf_string_conversions.h" #include "chromeos/ui/vector_icons/vector_icons.h" +#include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/compositor/callback_layer_animation_observer.h" @@ -452,7 +453,8 @@ params.tooltip_id = IDS_ASH_ASSISTANT_DIALOG_PLATE_KEYBOARD_TOOLTIP; keyboard_input_toggle_ = voice_layout_container->AddChildView(AssistantButton::Create( - this, kKeyboardIcon, AssistantButtonId::kKeyboardInputToggle, + this, vector_icons::kKeyboardIcon, + AssistantButtonId::kKeyboardInputToggle, std::move(params))); keyboard_input_toggle_->SetID(AssistantViewID::kKeyboardInputToggle);
diff --git a/ash/app_list/views/assistant/assistant_dialog_plate_unittest.cc b/ash/app_list/views/assistant/assistant_dialog_plate_unittest.cc index ce8b0a2..697cb094b 100644 --- a/ash/app_list/views/assistant/assistant_dialog_plate_unittest.cc +++ b/ash/app_list/views/assistant/assistant_dialog_plate_unittest.cc
@@ -17,6 +17,7 @@ #include "ash/style/ash_color_provider.h" #include "base/test/scoped_feature_list.h" #include "chromeos/constants/chromeos_features.h" +#include "components/vector_icons/vector_icons.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/image/image_unittest_util.h" @@ -55,8 +56,8 @@ ColorProvider::Get()->GetContentLayerColor( ColorProvider::ContentLayerType::kTextColorPrimary)); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconDipSize, gfx::kGoogleGrey900) - .bitmap(), + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconDipSize, + gfx::kGoogleGrey900).bitmap(), *keyboard_input_toggle->GetImage(views::Button::STATE_NORMAL).bitmap())); Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean( @@ -67,8 +68,8 @@ ColorProvider::Get()->GetContentLayerColor( ColorProvider::ContentLayerType::kTextColorPrimary)); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconDipSize, gfx::kGoogleGrey200) - .bitmap(), + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconDipSize, + gfx::kGoogleGrey200).bitmap(), *keyboard_input_toggle->GetImage(views::Button::STATE_NORMAL).bitmap())); } @@ -91,8 +92,8 @@ EXPECT_EQ(assistant_text_field->GetTextColor(), kTextColorPrimary); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconDipSize, gfx::kGoogleGrey900) - .bitmap(), + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconDipSize, + gfx::kGoogleGrey900).bitmap(), *keyboard_input_toggle->GetImage(views::Button::STATE_NORMAL).bitmap())); // Avoid test teardown issues by explicitly closing the launcher.
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc index ac63baa..735e7d8 100644 --- a/ash/app_list/views/search_result_view.cc +++ b/ash/app_list/views/search_result_view.cc
@@ -96,6 +96,8 @@ constexpr gfx::Insets kAnswerCardBorder(kAnswerCardBorderMargin); constexpr auto kBigTitleBorder = gfx::Insets::TLBR(0, 0, 0, kAnswerCardBorderMargin); +// The superscript container has a 4px left margin and 3px top margin. +constexpr auto kBigTitleSuperscriptBorder = gfx::Insets::TLBR(3, 4, 0, 0); // The fraction of total text space allocated to the details label when both the // title and the details label need to be elided. @@ -116,7 +118,8 @@ SearchResultView::SearchResultViewType view_type, SearchResultView::LabelType label_type, int flex_order, - bool elidable) { + bool elidable, + bool has_keyboard_shortcut_contents) { // Create and setup label. views::Label* label = parent->AddChildView(std::make_unique<views::Label>()); // Ignore labels for accessibility - the result accessible name is defined on @@ -133,9 +136,34 @@ .WithOrder(flex_order)); // Apply label text styling. - label->SetTextContext(label_type == SearchResultView::LabelType::kBigTitle - ? CONTEXT_SEARCH_RESULT_BIG_TITLE - : CONTEXT_SEARCH_RESULT_VIEW); + ash::AshTextContext text_context; + switch (label_type) { + case SearchResultView::LabelType::kBigTitle: + text_context = CONTEXT_SEARCH_RESULT_BIG_TITLE; + break; + case SearchResultView::LabelType::kBigTitleSuperscript: + // kBigTitleSuperscript labels are top-aligned to support superscripting. + label->SetVerticalAlignment(gfx::ALIGN_TOP); + text_context = CONTEXT_SEARCH_RESULT_BIG_TITLE_SUPERSCRIPT; + break; + case SearchResultView::LabelType::kTitle: + text_context = CONTEXT_SEARCH_RESULT_VIEW; + break; + case SearchResultView::LabelType::kDetails: + // has_keyboard_shortcut_contents forces inline title and details text for + // answer cards so title and details text should use the same context. + if (view_type == SearchResultView::SearchResultViewType::kAnswerCard && + !has_keyboard_shortcut_contents) { + text_context = CONTEXT_SEARCH_RESULT_VIEW_INLINE_ANSWER_DETAILS; + } else { + text_context = CONTEXT_SEARCH_RESULT_VIEW; + } + break; + case SearchResultView::LabelType::kKeyboardShortcut: + text_context = CONTEXT_SEARCH_RESULT_VIEW; + break; + } + label->SetTextContext(text_context); switch (view_type) { case SearchResultView::SearchResultViewType::kClassic: label->SetTextStyle(STYLE_CLASSIC_LAUNCHER); @@ -282,6 +310,23 @@ text_container_->AddChildView(std::make_unique<views::FlexLayoutView>()); big_title_container_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch); big_title_container_->SetBorder(views::CreateEmptyBorder(kBigTitleBorder)); + big_title_container_->SetOrientation(views::LayoutOrientation::kHorizontal); + + big_title_main_text_container_ = big_title_container_->AddChildView( + std::make_unique<views::FlexLayoutView>()); + big_title_main_text_container_->SetCrossAxisAlignment( + views::LayoutAlignment::kStretch); + big_title_main_text_container_->SetOrientation( + views::LayoutOrientation::kHorizontal); + + big_title_superscript_container_ = big_title_container_->AddChildView( + std::make_unique<views::FlexLayoutView>()); + big_title_superscript_container_->SetCrossAxisAlignment( + views::LayoutAlignment::kStretch); + big_title_superscript_container_->SetBorder( + views::CreateEmptyBorder(kBigTitleSuperscriptBorder)); + big_title_superscript_container_->SetOrientation( + views::LayoutOrientation::kHorizontal); body_text_container_ = text_container_->AddChildView(std::make_unique<views::FlexLayoutView>()); @@ -302,13 +347,6 @@ views::MaximumFlexSizeRule::kPreferred)); SetSearchResultViewType(view_type_); - keyboard_shortcut_container_ = body_text_container_->AddChildView( - std::make_unique<views::FlexLayoutView>()); - keyboard_shortcut_container_->SetCrossAxisAlignment( - views::LayoutAlignment::kStretch); - keyboard_shortcut_container_->SetBorder(views::CreateEmptyBorder( - gfx::Insets::TLBR(kKeyboardShortcutTopMargin, 0, 0, 0))); - title_container_ = title_and_details_container_->AddChildView( std::make_unique<views::FlexLayoutView>()); title_container_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch); @@ -322,9 +360,9 @@ title_container_->SetFlexAllocationOrder( views::FlexAllocationOrder::kReverse); - separator_label_ = - SetupChildLabelView(title_and_details_container_, view_type_, - LabelType::kDetails, kSeparatorOrder, false); + separator_label_ = SetupChildLabelView( + title_and_details_container_, view_type_, LabelType::kDetails, + kSeparatorOrder, /*elidable=*/false, has_keyboard_shortcut_contents_); separator_label_->SetText( l10n_util::GetStringUTF16(IDS_ASH_SEARCH_RESULT_SEPARATOR)); separator_label_->GetViewAccessibility().OverrideIsIgnored(true); @@ -340,8 +378,9 @@ .WithOrder(kTitleDetailsContainerOrderNoElide) .WithWeight(1)); - rating_ = SetupChildLabelView(title_and_details_container_, view_type_, - LabelType::kDetails, kRatingOrder, false); + rating_ = SetupChildLabelView( + title_and_details_container_, view_type_, LabelType::kDetails, + kRatingOrder, /*elidable=*/false, has_keyboard_shortcut_contents_); rating_star_ = SetupChildImageView(title_and_details_container_); rating_star_->SetImage(gfx::CreateVectorIcon( @@ -350,6 +389,13 @@ kDeprecatedSearchBoxTextDefaultColor))); rating_star_->SetBorder(views::CreateEmptyBorder( gfx::Insets::TLBR(0, kSearchRatingStarPadding, 0, 0))); + + keyboard_shortcut_container_ = body_text_container_->AddChildView( + std::make_unique<views::FlexLayoutView>()); + keyboard_shortcut_container_->SetCrossAxisAlignment( + views::LayoutAlignment::kStretch); + keyboard_shortcut_container_->SetBorder(views::CreateEmptyBorder( + gfx::Insets::TLBR(kKeyboardShortcutTopMargin, 0, 0, 0))); } SearchResultView::~SearchResultView() = default; @@ -371,23 +417,16 @@ void SearchResultView::SetSearchResultViewType(SearchResultViewType type) { view_type_ = type; - switch (view_type_) { case SearchResultViewType::kDefault: title_and_details_container_->SetOrientation( views::LayoutOrientation::kHorizontal); - SetBorder(views::CreateEmptyBorder(0)); - big_title_container_->RemoveAllChildViews(); - big_title_label_tags_.clear(); - big_title_container_->SetVisible(false); + ClearBigTitleContainer(); break; case SearchResultViewType::kClassic: title_and_details_container_->SetOrientation( views::LayoutOrientation::kVertical); - SetBorder(views::CreateEmptyBorder(0)); - big_title_container_->RemoveAllChildViews(); - big_title_label_tags_.clear(); - big_title_container_->SetVisible(false); + ClearBigTitleContainer(); break; case SearchResultViewType::kAnswerCard: title_and_details_container_->SetOrientation( @@ -397,6 +436,16 @@ } } +void SearchResultView::ClearBigTitleContainer() { + SetBorder(views::CreateEmptyBorder(0)); + big_title_main_text_container_->RemoveAllChildViews(); + big_title_label_tags_.clear(); + big_title_main_text_container_->SetVisible(false); + big_title_superscript_container_->RemoveAllChildViews(); + big_title_superscript_label_tags_.clear(); + big_title_superscript_container_->SetVisible(false); +} + views::LayoutOrientation SearchResultView::TitleAndDetailsOrientationForTest() { return title_and_details_container_->GetOrientation(); } @@ -559,7 +608,8 @@ SearchResultView::SetupContainerViewForTextVector( views::FlexLayoutView* parent, const std::vector<SearchResult::TextItem>& text_vector, - LabelType label_type) { + LabelType label_type, + bool has_keyboard_shortcut_contents) { std::vector<LabelAndTag> label_tags; // Updating the details label should reset our pointer to the last seen // `non_elide_label_`. `non_elide_label_` can only be found in the details @@ -576,7 +626,7 @@ parent, view_type_, label_type, elidable ? kElidableLabelOrderStart + label_count : kNonElideLabelOrder, - elidable); + elidable, has_keyboard_shortcut_contents); // Elidable label orders are monotonically increasing. Adjust the order // of the label by the number of labels in this container. if (elidable) @@ -652,17 +702,35 @@ void SearchResultView::UpdateBigTitleContainer() { DCHECK_EQ(view_type_, SearchResultViewType::kAnswerCard); // Big title is only shown for answer card views. - big_title_container_->RemoveAllChildViews(); + big_title_main_text_container_->RemoveAllChildViews(); big_title_label_tags_.clear(); if (!result() || result()->big_title_text_vector().empty()) { - big_title_container_->SetVisible(false); + big_title_main_text_container_->SetVisible(false); } else { - // Create title labels from text vector metadata. + // Create big title labels from text vector metadata. big_title_label_tags_ = SetupContainerViewForTextVector( - big_title_container_, result()->big_title_text_vector(), - LabelType::kBigTitle); + big_title_main_text_container_, result()->big_title_text_vector(), + LabelType::kBigTitle, has_keyboard_shortcut_contents_); StyleBigTitleContainer(); - big_title_container_->SetVisible(true); + big_title_main_text_container_->SetVisible(true); + } +} + +void SearchResultView::UpdateBigTitleSuperscriptContainer() { + DCHECK_EQ(view_type_, SearchResultViewType::kAnswerCard); + // Big title superscript is only shown for answer card views. + big_title_superscript_container_->RemoveAllChildViews(); + big_title_superscript_label_tags_.clear(); + if (!result() || result()->big_title_superscript_text_vector().empty()) { + big_title_superscript_container_->SetVisible(false); + } else { + // Create big title superscript labels from text vector metadata. + big_title_superscript_label_tags_ = SetupContainerViewForTextVector( + big_title_superscript_container_, + result()->big_title_superscript_text_vector(), + LabelType::kBigTitleSuperscript, has_keyboard_shortcut_contents_); + StyleBigTitleSuperscriptContainer(); + big_title_superscript_container_->SetVisible(true); } } @@ -677,7 +745,8 @@ } else { // Create title labels from text vector metadata. title_label_tags_ = SetupContainerViewForTextVector( - title_container_, result()->title_text_vector(), LabelType::kTitle); + title_container_, result()->title_text_vector(), LabelType::kTitle, + has_keyboard_shortcut_contents_); StyleTitleContainer(); text_container_->SetVisible(true); title_and_details_container_->SetVisible(true); @@ -696,7 +765,7 @@ // Create details labels from text vector metadata. details_label_tags_ = SetupContainerViewForTextVector( details_container_, result()->details_text_vector(), - LabelType::kDetails); + LabelType::kDetails, has_keyboard_shortcut_contents_); StyleDetailsContainer(); details_container_->SetVisible(true); switch (view_type_) { @@ -740,12 +809,12 @@ break; } } else { + has_keyboard_shortcut_contents_ = true; keyboard_shortcut_container_tags_ = SetupContainerViewForTextVector( keyboard_shortcut_container_, result()->keyboard_shortcut_text_vector(), - LabelType::kKeyboardShortcut); + LabelType::kKeyboardShortcut, has_keyboard_shortcut_contents_); StyleKeyboardShortcutContainer(); keyboard_shortcut_container_->SetVisible(true); - has_keyboard_shortcut_contents_ = true; // Override `title_and_details_container_` orientation if the keyboard // shortcut text vector has valid contents. title_and_details_container_->SetOrientation( @@ -839,6 +908,12 @@ } } +void SearchResultView::StyleBigTitleSuperscriptContainer() { + for (auto& span : big_title_superscript_label_tags_) { + StyleLabel(span.GetLabel(), true /*is_title_label*/, span.GetTags()); + } +} + void SearchResultView::StyleTitleContainer() { for (auto& span : title_label_tags_) { StyleLabel(span.GetLabel(), true /*is_title_label*/, span.GetTags()); @@ -1124,8 +1199,10 @@ } void SearchResultView::OnMetadataChanged() { - if (view_type_ == SearchResultViewType::kAnswerCard) + if (view_type_ == SearchResultViewType::kAnswerCard) { UpdateBigTitleContainer(); + UpdateBigTitleSuperscriptContainer(); + } if (view_type_ != SearchResultViewType::kClassic && app_list_features::IsSearchResultInlineIconEnabled()) { UpdateKeyboardShortcutContainer();
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h index bc1634c0..9eb130f 100644 --- a/ash/app_list/views/search_result_view.h +++ b/ash/app_list/views/search_result_view.h
@@ -48,6 +48,13 @@ // | +----------------------+ +----------------------------------+ | // +---------------------------------------------------------------+ // +// +-------------------------------------------------------------------------+ +// |`big_title_container_` | +// | +--------------------------------+ +----------------------------------+ | +// | |'big_title_main_text_container_'| |`big_title_superscript_container_`| | +// | +--------------------------------+ +----------------------------------+ | +// +-------------------------------------------------------------------------+ +// // The `title_and_details_container_` has two possible layouts depending on // `view_type_` and whether `keyboard_shortcut_container_` has results // @@ -90,6 +97,7 @@ enum class LabelType { kBigTitle, + kBigTitleSuperscript, kTitle, kDetails, kKeyboardShortcut, @@ -113,6 +121,7 @@ void OnResultChanged() override; void SetSearchResultViewType(SearchResultViewType type); + void ClearBigTitleContainer(); SearchResultViewType view_type() { return view_type_; } views::LayoutOrientation TitleAndDetailsOrientationForTest(); @@ -153,9 +162,11 @@ std::vector<LabelAndTag> SetupContainerViewForTextVector( views::FlexLayoutView* parent, const std::vector<SearchResult::TextItem>& text_vector, - LabelType label_type); + LabelType label_type, + bool has_keyboard_shortcut_contents); void UpdateBadgeIcon(); void UpdateBigTitleContainer(); + void UpdateBigTitleSuperscriptContainer(); void UpdateTitleContainer(); void UpdateDetailsContainer(); void UpdateKeyboardShortcutContainer(); @@ -165,6 +176,7 @@ bool is_title_label, const SearchResult::Tags& tags); void StyleBigTitleContainer(); + void StyleBigTitleSuperscriptContainer(); void StyleTitleContainer(); void StyleDetailsContainer(); void StyleKeyboardShortcutContainer(); @@ -214,6 +226,10 @@ nullptr; // Owned by views hierarchy. views::FlexLayoutView* big_title_container_ = nullptr; // Owned by views hierarchy. + views::FlexLayoutView* big_title_main_text_container_ = + nullptr; // Owned by views hierarchy. + views::FlexLayoutView* big_title_superscript_container_ = + nullptr; // Owned by views hierarchy. views::FlexLayoutView* body_text_container_ = nullptr; // Owned by views hierarchy. views::FlexLayoutView* title_and_details_container_ = @@ -225,6 +241,8 @@ views::FlexLayoutView* keyboard_shortcut_container_ = nullptr; // Owned by views hierarchy. std::vector<LabelAndTag> big_title_label_tags_; // Owned by views hierarchy. + std::vector<LabelAndTag> + big_title_superscript_label_tags_; // Owned by views hierarchy. std::vector<LabelAndTag> title_label_tags_; // Owned by views hierarchy. std::vector<LabelAndTag> details_label_tags_; // Owned by views hierarchy. std::vector<LabelAndTag>
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 275c4b4..e291e7a 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -21,6 +21,7 @@ <output filename="ash_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ash_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ash_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ash_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ash_strings_da.pak" type="data_package" lang="da" /> <output filename="ash_strings_de.pak" type="data_package" lang="de" /> <output filename="ash_strings_el.pak" type="data_package" lang="el" />
diff --git a/ash/assistant/model/ui/assistant_card_element.cc b/ash/assistant/model/ui/assistant_card_element.cc index 40d4ed7..d0d5324629 100644 --- a/ash/assistant/model/ui/assistant_card_element.cc +++ b/ash/assistant/model/ui/assistant_card_element.cc
@@ -95,6 +95,10 @@ processor_->Process(); } +bool AssistantCardElement::has_contents_view() const { + return !!contents_view_; +} + bool AssistantCardElement::Compare(const AssistantUiElement& other) const { return other.type() == AssistantUiElementType::kCard && static_cast<const AssistantCardElement&>(other).html() == html_;
diff --git a/ash/assistant/model/ui/assistant_card_element.h b/ash/assistant/model/ui/assistant_card_element.h index 6044ef3c..8e40212e 100644 --- a/ash/assistant/model/ui/assistant_card_element.h +++ b/ash/assistant/model/ui/assistant_card_element.h
@@ -30,6 +30,7 @@ // AssistantUiElement: void Process(ProcessingCallback callback) override; + bool has_contents_view() const; const std::string& html() const { return html_; } const std::string& fallback() const { return fallback_; } std::unique_ptr<AshWebView> MoveContentsView() {
diff --git a/ash/assistant/ui/BUILD.gn b/ash/assistant/ui/BUILD.gn index 83c285f..39fc65b 100644 --- a/ash/assistant/ui/BUILD.gn +++ b/ash/assistant/ui/BUILD.gn
@@ -99,6 +99,7 @@ "//chromeos/services/assistant/public/mojom", "//chromeos/services/libassistant/public/cpp:structs", "//chromeos/ui/vector_icons", + "//components/vector_icons", "//ui/aura", "//ui/chromeos/styles:cros_styles_views", "//ui/compositor",
diff --git a/ash/assistant/ui/DEPS b/ash/assistant/ui/DEPS index 17f1d5c..15d906f 100644 --- a/ash/assistant/ui/DEPS +++ b/ash/assistant/ui/DEPS
@@ -44,6 +44,7 @@ "+chromeos/ui/frame/default_frame_header.h", "+chromeos/ui/vector_icons/vector_icons.h", "+components/prefs", + "+components/vector_icons", "+testing/gmock", "+testing/gtest", ],
diff --git a/ash/assistant/ui/base/assistant_button_unittest.cc b/ash/assistant/ui/base/assistant_button_unittest.cc index 9c5fe01..9a7b06e 100644 --- a/ash/assistant/ui/base/assistant_button_unittest.cc +++ b/ash/assistant/ui/base/assistant_button_unittest.cc
@@ -18,6 +18,7 @@ #include "base/test/scoped_feature_list.h" #include "chromeos/constants/chromeos_features.h" #include "components/prefs/pref_service.h" +#include "components/vector_icons/vector_icons.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" @@ -44,7 +45,8 @@ gfx::Canvas expected(gfx::Size(kSizeInDip, kSizeInDip), /*image_scale=*/1.0f, /*is_opaque=*/true); expected.DrawImageInt( - gfx::CreateVectorIcon(kKeyboardIcon, kIconSizeInDip, icon_color), + gfx::CreateVectorIcon( + vector_icons::kKeyboardIcon, kIconSizeInDip, icon_color), kIconOffset, kIconOffset); cc::PaintFlags circle_flags; @@ -70,11 +72,11 @@ params.accessible_name_id = IDS_ASH_ASSISTANT_DIALOG_PLATE_KEYBOARD_ACCNAME; std::unique_ptr<AssistantButton> button = AssistantButton::Create( - nullptr, kKeyboardIcon, AssistantButtonId::kKeyboardInputToggle, - std::move(params)); + nullptr, vector_icons::kKeyboardIcon, + AssistantButtonId::kKeyboardInputToggle, std::move(params)); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconSizeInDip, gfx::kGoogleBlue900) - .bitmap(), + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconSizeInDip, + gfx::kGoogleBlue900).bitmap(), *button->GetImage(views::Button::STATE_NORMAL).bitmap())); } @@ -88,11 +90,11 @@ params.icon_color_type = ColorProvider::ContentLayerType::kIconColorPrimary; std::unique_ptr<AssistantButton> button = AssistantButton::Create( - nullptr, kKeyboardIcon, AssistantButtonId::kKeyboardInputToggle, - std::move(params)); + nullptr, vector_icons::kKeyboardIcon, + AssistantButtonId::kKeyboardInputToggle, std::move(params)); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconSizeInDip, + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconSizeInDip, ash::features::IsProductivityLauncherEnabled() ? gfx::kGoogleGrey200 : gfx::kGoogleGrey900) @@ -116,13 +118,13 @@ params.icon_color_type = ColorProvider::ContentLayerType::kIconColorPrimary; std::unique_ptr<AssistantButton> button = AssistantButton::Create( - nullptr, kKeyboardIcon, AssistantButtonId::kKeyboardInputToggle, - std::move(params)); + nullptr, vector_icons::kKeyboardIcon, + AssistantButtonId::kKeyboardInputToggle, std::move(params)); ASSERT_FALSE(ColorProvider::Get()->IsDarkModeEnabled()); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconSizeInDip, gfx::kGoogleGrey900) - .bitmap(), + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconSizeInDip, + gfx::kGoogleGrey900).bitmap(), *button->GetImage(views::Button::STATE_NORMAL).bitmap())); // Switch to dark mode @@ -135,8 +137,8 @@ button->OnThemeChanged(); EXPECT_TRUE(gfx::test::AreBitmapsEqual( - *gfx::CreateVectorIcon(kKeyboardIcon, kIconSizeInDip, gfx::kGoogleGrey200) - .bitmap(), + *gfx::CreateVectorIcon(vector_icons::kKeyboardIcon, kIconSizeInDip, + gfx::kGoogleGrey200).bitmap(), *button->GetImage(views::Button::STATE_NORMAL).bitmap())); } @@ -152,8 +154,8 @@ std::unique_ptr<views::Widget> widget = CreateTestWidget(); AssistantButton* button = widget->GetContentsView()->AddChildView(AssistantButton::Create( - nullptr, kKeyboardIcon, AssistantButtonId::kKeyboardInputToggle, - std::move(params))); + nullptr, vector_icons::kKeyboardIcon, + AssistantButtonId::kKeyboardInputToggle, std::move(params))); button->SizeToPreferredSize(); button->RequestFocus(); @@ -188,8 +190,8 @@ std::unique_ptr<views::Widget> widget = CreateTestWidget(); AssistantButton* button = widget->GetContentsView()->AddChildView(AssistantButton::Create( - nullptr, kKeyboardIcon, AssistantButtonId::kKeyboardInputToggle, - std::move(params))); + nullptr, vector_icons::kKeyboardIcon, + AssistantButtonId::kKeyboardInputToggle, std::move(params))); button->SizeToPreferredSize(); button->RequestFocus();
diff --git a/ash/assistant/ui/main_stage/assistant_ui_element_view_factory.cc b/ash/assistant/ui/main_stage/assistant_ui_element_view_factory.cc index 2aa5130..96fcb30 100644 --- a/ash/assistant/ui/main_stage/assistant_ui_element_view_factory.cc +++ b/ash/assistant/ui/main_stage/assistant_ui_element_view_factory.cc
@@ -13,6 +13,7 @@ #include "ash/assistant/ui/main_stage/assistant_error_element_view.h" #include "ash/assistant/ui/main_stage/assistant_text_element_view.h" #include "ash/assistant/ui/main_stage/assistant_ui_element_view.h" +#include "base/logging.h" namespace ash { @@ -25,9 +26,17 @@ std::unique_ptr<AssistantUiElementView> AssistantUiElementViewFactory::Create( const AssistantUiElement* ui_element) const { switch (ui_element->type()) { - case AssistantUiElementType::kCard: - return std::make_unique<AssistantCardElementView>( - delegate_, static_cast<const AssistantCardElement*>(ui_element)); + case AssistantUiElementType::kCard: { + auto* card_element = static_cast<const AssistantCardElement*>(ui_element); + if (!card_element->has_contents_view()) { + // TODO(b/228109139): Find the root cause why reaches here. + LOG(DFATAL) << "AssistantCardElement has null contents_view. Not " + "create the view."; + return nullptr; + } + return std::make_unique<AssistantCardElementView>(delegate_, + card_element); + } case AssistantUiElementType::kError: return std::make_unique<AssistantErrorElementView>( static_cast<const AssistantErrorElement*>(ui_element));
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view.cc b/ash/assistant/ui/main_stage/ui_element_container_view.cc index d63340ab..bc3909a9 100644 --- a/ash/assistant/ui/main_stage/ui_element_container_view.cc +++ b/ash/assistant/ui/main_stage/ui_element_container_view.cc
@@ -209,6 +209,9 @@ const AssistantUiElement* ui_element) { // Create a new view for the |ui_element|. auto view = view_factory_->Create(ui_element); + if (!view) { + return nullptr; + } // If the first UI element is a card, it has a unique margin requirement. const bool is_card = ui_element->type() == AssistantUiElementType::kCard;
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc index 47c56a5e..259c658 100644 --- a/ash/clipboard/clipboard_history_menu_model_adapter.cc +++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -378,9 +378,6 @@ // `ChildrenChanged()` clears the selection. So restore the selection. if (original_selected_command_id.has_value()) SelectMenuItemWithCommandId(*original_selected_command_id); - - if (item_removal_callback_for_test_) - item_removal_callback_for_test_.Run(); } views::MenuItemView* ClipboardHistoryMenuModelAdapter::AppendMenuItem(
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.h b/ash/clipboard/clipboard_history_menu_model_adapter.h index 3eebb80..cd068ce 100644 --- a/ash/clipboard/clipboard_history_menu_model_adapter.h +++ b/ash/clipboard/clipboard_history_menu_model_adapter.h
@@ -92,10 +92,6 @@ const views::MenuItemView* GetMenuItemViewAtForTest(int index) const; views::MenuItemView* GetMenuItemViewAtForTest(int index); - void set_item_removal_callback_for_test(base::RepeatingClosure new_callback) { - item_removal_callback_for_test_ = std::move(new_callback); - } - private: class ScopedA11yIgnore; @@ -160,9 +156,6 @@ // Indicates whether `Run()` has been called before. bool run_before_ = false; - // Called when an item view is removed from the root menu. - base::RepeatingClosure item_removal_callback_for_test_; - base::WeakPtrFactory<ClipboardHistoryMenuModelAdapter> weak_ptr_factory_{ this}; };
diff --git a/ash/components/arc/metrics/arc_metrics_service.cc b/ash/components/arc/metrics/arc_metrics_service.cc index 26af0fb8..0419dd3 100644 --- a/ash/components/arc/metrics/arc_metrics_service.cc +++ b/ash/components/arc/metrics/arc_metrics_service.cc
@@ -568,6 +568,7 @@ number_of_failures, kUmaFixupAppsCountMin, kUmaFixupAppsCountMax, kUmaNumBuckets); } + void ArcMetricsService::ReportPerAppFixupMetrics( base::TimeDelta duration, uint32_t number_of_directories) { @@ -578,6 +579,7 @@ kUmaFixupDirectoriesCountMin, kUmaFixupDirectoriesCountMax, kUmaNumBuckets); } + void ArcMetricsService::ReportMainAccountHashMigrationMetrics( mojom::MainAccountHashMigrationStatus status) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -641,6 +643,12 @@ } } +void ArcMetricsService::ReportWaylandLateTimingDuration( + base::TimeDelta duration) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + base::UmaHistogramLongTimes("Arc.Wayland.LateTiming.Duration", duration); +} + void ArcMetricsService::OnWindowActivated( wm::ActivationChangeObserver::ActivationReason reason, aura::Window* gained_active,
diff --git a/ash/components/arc/metrics/arc_metrics_service.h b/ash/components/arc/metrics/arc_metrics_service.h index ede47bb0..98597d1 100644 --- a/ash/components/arc/metrics/arc_metrics_service.h +++ b/ash/components/arc/metrics/arc_metrics_service.h
@@ -146,6 +146,7 @@ int64_t duration_ms) override; void ReportMemoryPressure(const std::vector<uint8_t>& psiFile) override; void ReportProvisioningPreSignIn() override; + void ReportWaylandLateTimingDuration(base::TimeDelta duration) override; // wm::ActivationChangeObserver overrides. // Records to UMA when a user has interacted with an ARC app window.
diff --git a/ash/components/arc/mojom/metrics.mojom b/ash/components/arc/mojom/metrics.mojom index 051819ce..ef2d158b 100644 --- a/ash/components/arc/mojom/metrics.mojom +++ b/ash/components/arc/mojom/metrics.mojom
@@ -1,7 +1,7 @@ // Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 23 +// Next MinVersion: 24 module arc.mojom; @@ -330,7 +330,7 @@ // tools/metrics/histograms/enums.xml. }; -// Next method ID: 24 +// Next method ID: 26 interface MetricsHost { // Reports boot progress events from ARC instance. ReportBootProgress@0(array<BootProgressEvent> events, @@ -431,6 +431,10 @@ // Reports that ArcAppLauncher is about to start GMS sign-in / CloudDPC // provisioning. This only happens during ARC provisioning. [MinVersion=22] ReportProvisioningPreSignIn@24(); + + // Reports the duration of late timing events for Wayland. + [MinVersion=23] ReportWaylandLateTimingDuration@25( + mojo_base.mojom.TimeDelta duration); }; // Deprecated method IDs: 0
diff --git a/ash/public/cpp/ash_typography.cc b/ash/public/cpp/ash_typography.cc index 9283cb3..2a2750b 100644 --- a/ash/public/cpp/ash_typography.cc +++ b/ash/public/cpp/ash_typography.cc
@@ -42,6 +42,9 @@ break; case CONTEXT_SEARCH_RESULT_BIG_TITLE: details.size_delta = 24; + break; + case CONTEXT_SEARCH_RESULT_BIG_TITLE_SUPERSCRIPT: + details.size_delta = 6; } switch (style) {
diff --git a/ash/public/cpp/ash_typography.h b/ash/public/cpp/ash_typography.h index d40062d..725a161 100644 --- a/ash/public/cpp/ash_typography.h +++ b/ash/public/cpp/ash_typography.h
@@ -50,6 +50,9 @@ // Big title text label used in search result view. Usually 36 pt. CONTEXT_SEARCH_RESULT_BIG_TITLE, + // Big title superscript text label used in search result view. Usually 18 pt. + CONTEXT_SEARCH_RESULT_BIG_TITLE_SUPERSCRIPT, + // Details text label used for inline answer search result view. Usually 12pt. // Used when productivity launcher is enabled. CONTEXT_SEARCH_RESULT_VIEW_INLINE_ANSWER_DETAILS,
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index a4706ddb..b3a81b7 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -101,7 +101,6 @@ "ime_menu_on_screen_keyboard.icon", "ime_menu_write.icon", "ink_pen.icon", - "keyboard.icon", "ksv_arrow_down.icon", "ksv_arrow_left.icon", "ksv_arrow_right.icon",
diff --git a/ash/shortcut_viewer/shortcut_viewer_strings.grd b/ash/shortcut_viewer/shortcut_viewer_strings.grd index 400a0ab..109ec4b5 100644 --- a/ash/shortcut_viewer/shortcut_viewer_strings.grd +++ b/ash/shortcut_viewer/shortcut_viewer_strings.grd
@@ -17,6 +17,7 @@ <output filename="shortcut_viewer_strings_bs.pak" type="data_package" lang="bs" /> <output filename="shortcut_viewer_strings_ca.pak" type="data_package" lang="ca" /> <output filename="shortcut_viewer_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="shortcut_viewer_strings_cy.pak" type="data_package" lang="cy" /> <output filename="shortcut_viewer_strings_da.pak" type="data_package" lang="da" /> <output filename="shortcut_viewer_strings_de.pak" type="data_package" lang="de" /> <output filename="shortcut_viewer_strings_el.pak" type="data_package" lang="el" />
diff --git a/ash/system/accessibility/dictation_bubble_view.cc b/ash/system/accessibility/dictation_bubble_view.cc index 01d6ce01..3ac725d 100644 --- a/ash/system/accessibility/dictation_bubble_view.cc +++ b/ash/system/accessibility/dictation_bubble_view.cc
@@ -10,7 +10,9 @@ #include "ash/constants/ash_features.h" #include "ash/public/cpp/accessibility_controller_enums.h" #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" +#include "ash/public/cpp/shell_window_ids.h" #include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" #include "cc/paint/skottie_wrapper.h" @@ -308,7 +310,9 @@ DictationBubbleView::DictationBubbleView() { SetButtons(ui::DIALOG_BUTTON_NONE); - set_has_parent(false); + set_parent_window( + Shell::GetContainer(Shell::GetPrimaryRootWindow(), + kShellWindowId_AccessibilityBubbleContainer)); } DictationBubbleView::~DictationBubbleView() = default;
diff --git a/ash/system/cast/tray_cast.cc b/ash/system/cast/tray_cast.cc index d9896107..65962e3 100644 --- a/ash/system/cast/tray_cast.cc +++ b/ash/system/cast/tray_cast.cc
@@ -117,7 +117,7 @@ // receivers. if (CastConfigController::Get()->AccessCodeCastingEnabled()) { add_access_code_device_ = AddScrollListItem( - vector_icons::kQrCodeIcon, + vector_icons::kKeyboardIcon, l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_CAST_ACCESS_CODE_CAST_CONNECT)); }
diff --git a/ash/system/eche/eche_icon_loading_indicator_view.cc b/ash/system/eche/eche_icon_loading_indicator_view.cc index 7aec4ff9..4eabbeb 100644 --- a/ash/system/eche/eche_icon_loading_indicator_view.cc +++ b/ash/system/eche/eche_icon_loading_indicator_view.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/system/eche/eche_icon_loading_indicator_view.h" +#include <algorithm> #include "ash/session/session_controller_impl.h" #include "ash/shell.h" @@ -24,7 +25,7 @@ namespace { -constexpr int kThrobberStrokeWidth = 2; +constexpr int kThrobberStrokeWidth = 3; } // namespace @@ -59,10 +60,12 @@ if (!throbber_start_time_) return; - // The image covers the container horizontally and is centered vertically. + // The image covers the container on the main axiz and is centered on the + // other axis. So we get the minimum of the height and width. + int spinner_size_dip = + std::min(GetLocalBounds().width(), GetLocalBounds().height()); gfx::Rect bounds = GetLocalBounds(); - bounds.ClampToCenteredSize( - gfx::Size(GetLocalBounds().width(), GetLocalBounds().width())); + bounds.ClampToCenteredSize(gfx::Size(spinner_size_dip, spinner_size_dip)); gfx::PaintThrobberSpinning( canvas, bounds, TrayIconColor(Shell::Get()->session_controller()->GetSessionState()),
diff --git a/ash/system/eche/eche_tray.cc b/ash/system/eche/eche_tray.cc index 1c72e431..f03fc51c 100644 --- a/ash/system/eche/eche_tray.cc +++ b/ash/system/eche/eche_tray.cc
@@ -62,6 +62,10 @@ // padding becoming negative. constexpr int kIconSize = 22; +// This is how much the icon shrinks to give space for the spinner to go +// around it. +constexpr int kIconShrinkSizeForSpinner = 4; + constexpr int kHeaderHeight = 40; constexpr int kHeaderHorizontalInteriorMargins = 0; constexpr auto kHeaderDefaultSpacing = gfx::Insets::VH(0, 6); @@ -440,7 +444,21 @@ return phone_hub_tray->eche_icon_view(); } +void EcheTray::ResizeIcon(int offset_dip) { + views::ImageButton* icon_view = GetIcon(); + if (icon_view) { + auto icon = icon_view->GetImage(views::ImageButton::STATE_NORMAL); + icon_view->SetImage( + views::ImageButton::STATE_NORMAL, + gfx::ImageSkiaOperations::CreateResizedImage( + icon, skia::ImageOperations::RESIZE_BEST, + gfx::Size(kIconSize - offset_dip, kIconSize - offset_dip))); + GetPhoneHubTray()->tray_container()->UpdateLayout(); + } +} + void EcheTray::StopLoadingAnimation() { + ResizeIcon(0); auto* loading_indicator = GetLoadingIndicator(); if (loading_indicator && loading_indicator->GetAnimating()) { loading_indicator->SetAnimating(false); @@ -448,6 +466,7 @@ } void EcheTray::StartLoadingAnimation() { + ResizeIcon(kIconShrinkSizeForSpinner); auto* loading_indicator = GetLoadingIndicator(); if (loading_indicator) { loading_indicator->SetAnimating(true);
diff --git a/ash/system/eche/eche_tray.h b/ash/system/eche/eche_tray.h index de2b0cc7..74848efa 100644 --- a/ash/system/eche/eche_tray.h +++ b/ash/system/eche/eche_tray.h
@@ -101,6 +101,10 @@ // Sets the icon that will be used on the tray. void SetIcon(const gfx::Image& icon, const std::u16string& tooltip_text); + // Reduces the size of the original icon by the `offset`. Passing a zero + // `offset` will bring the icon back to its original size. + void ResizeIcon(int offset_dip); + // Sets graceful close callback functiion. When close Eche Bubble, it will // notify to Eche Web to release connection resource. Be aware that once this // is set, close button will not call PurgeAndClose() but rely on Eche Web to
diff --git a/ash/system/eche/eche_tray_unittest.cc b/ash/system/eche/eche_tray_unittest.cc index 62808e26..0d850b3 100644 --- a/ash/system/eche/eche_tray_unittest.cc +++ b/ash/system/eche/eche_tray_unittest.cc
@@ -31,6 +31,18 @@ is_web_content_unloaded_ = false; } +SkBitmap TestBitmap() { + SkBitmap bitmap; + bitmap.allocN32Pixels(30, 30); + return bitmap; +} + +gfx::Image CreateTestImage() { + gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(TestBitmap()); + image_skia.MakeThreadSafe(); + return gfx::Image(image_skia); +} + } // namespace class EcheTrayTest : public AshTestBase { @@ -101,7 +113,8 @@ EXPECT_FALSE(eche_tray()->GetVisible()); eche_tray()->SetVisiblePreferred(true); - eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1"); + eche_tray()->LoadBubble(GURL("http://google.com"), CreateTestImage(), + u"app 1"); eche_tray()->ShowBubble(); EXPECT_TRUE(eche_tray()->is_active()); @@ -135,6 +148,27 @@ EXPECT_TRUE(eche_tray()->GetVisible()); } +TEST_F(EcheTrayTest, EcheTrayIconResize) { + eche_tray()->SetVisiblePreferred(true); + eche_tray()->LoadBubble(GURL("http://google.com"), CreateTestImage(), + u"app 1"); + eche_tray()->ShowBubble(); + + int image_width = phone_hub_tray() + ->eche_icon_view() + ->GetImage(views::ImageButton::STATE_NORMAL) + .width(); + + eche_tray()->ResizeIcon(2); + + int new_image_width = phone_hub_tray() + ->eche_icon_view() + ->GetImage(views::ImageButton::STATE_NORMAL) + .width(); + + EXPECT_EQ(image_width, new_image_width + 2); +} + TEST_F(EcheTrayTest, EcheTrayCreatesBubbleButHideFirst) { // Verify the eche tray button is not active, and the eche tray bubble // is not shown initially. @@ -143,7 +177,8 @@ // Allow us to create the bubble but it is not visible until we need this // bubble to show up. - eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1"); + eche_tray()->LoadBubble(GURL("http://google.com"), CreateTestImage(), + u"app 1"); EXPECT_FALSE(eche_tray()->is_active()); EXPECT_TRUE(eche_tray()->get_bubble_wrapper_for_test()); @@ -170,7 +205,8 @@ // Allow us to create the bubble but it is not visible until we need this // bubble to show up. - eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1"); + eche_tray()->LoadBubble(GURL("http://google.com"), CreateTestImage(), + u"app 1"); EXPECT_FALSE(eche_tray()->is_active()); EXPECT_TRUE(eche_tray()->get_bubble_wrapper_for_test()); @@ -197,7 +233,8 @@ } TEST_F(EcheTrayTest, EcheTrayMinimizeButtonClicked) { - eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1"); + eche_tray()->LoadBubble(GURL("http://google.com"), CreateTestImage(), + u"app 1"); eche_tray()->ShowBubble(); EXPECT_TRUE( @@ -213,7 +250,8 @@ TEST_F(EcheTrayTest, EcheTrayCloseButtonClicked) { ResetUnloadWebContent(); eche_tray()->SetGracefulCloseCallback(base::BindOnce(&UnloadWebContent)); - eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1"); + eche_tray()->LoadBubble(GURL("http://google.com"), CreateTestImage(), + u"app 1"); eche_tray()->ShowBubble(); ClickButton(eche_tray()->GetCloseButtonForTesting());
diff --git a/ash/system/phonehub/phone_hub_tray.cc b/ash/system/phonehub/phone_hub_tray.cc index 3d89e514..e4f324d 100644 --- a/ash/system/phonehub/phone_hub_tray.cc +++ b/ash/system/phonehub/phone_hub_tray.cc
@@ -45,6 +45,7 @@ // Padding for tray icons (dp; the button that shows the phone_hub menu). constexpr int kTrayIconMainAxisInset = 6; constexpr int kTrayIconCrossAxisInset = 0; +constexpr int kEcheIconMinSize = 22; constexpr auto kBubblePadding = gfx::Insets::TLBR(0, 0, kBubbleBottomPaddingDip, 0); @@ -64,6 +65,10 @@ &PhoneHubTray::EcheIconActivated, weak_factory_.GetWeakPtr())); eche_icon->SetImageVerticalAlignment( views::ImageButton::VerticalAlignment::ALIGN_MIDDLE); + eche_icon->SetImageHorizontalAlignment( + views::ImageButton::HorizontalAlignment::ALIGN_CENTER); + eche_icon->SetMinimumImageSize( + gfx::Size(kEcheIconMinSize, kEcheIconMinSize)); eche_icon->SetVisible(false); eche_loading_indicator_ = eche_icon->AddChildView( std::make_unique<EcheIconLoadingIndicatorView>(eche_icon.get()));
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings.grd b/ash/webui/camera_app_ui/resources/strings/camera_strings.grd index 3f6f012..e05f99acf 100644 --- a/ash/webui/camera_app_ui/resources/strings/camera_strings.grd +++ b/ash/webui/camera_app_ui/resources/strings/camera_strings.grd
@@ -17,6 +17,7 @@ <output filename="ash_camera_app_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ash_camera_app_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ash_camera_app_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ash_camera_app_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ash_camera_app_strings_da.pak" type="data_package" lang="da" /> <output filename="ash_camera_app_strings_de.pak" type="data_package" lang="de" /> <output filename="ash_camera_app_strings_el.pak" type="data_package" lang="el" />
diff --git a/ash/webui/diagnostics_ui/resources/BUILD.gn b/ash/webui/diagnostics_ui/resources/BUILD.gn index 7daeaac..54284da 100644 --- a/ash/webui/diagnostics_ui/resources/BUILD.gn +++ b/ash/webui/diagnostics_ui/resources/BUILD.gn
@@ -227,6 +227,8 @@ js_library("input_list") { deps = [ + ":diagnostics_browser_proxy", + ":diagnostics_types", ":input_card", ":keyboard_tester", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_utils.js b/ash/webui/diagnostics_ui/resources/diagnostics_utils.js index caaa7d4..1ac37f68 100644 --- a/ash/webui/diagnostics_ui/resources/diagnostics_utils.js +++ b/ash/webui/diagnostics_ui/resources/diagnostics_utils.js
@@ -59,7 +59,8 @@ return NavigationView.kSystem; case 'connectivity': return NavigationView.kConnectivity; - // TODO(ashleydp): Add input when ready to launch. + case 'input': + return NavigationView.kInput; default: assertNotReached(); return NavigationView.kSystem;
diff --git a/ash/webui/diagnostics_ui/resources/input_list.js b/ash/webui/diagnostics_ui/resources/input_list.js index fc4ad7a..26f787d9 100644 --- a/ash/webui/diagnostics_ui/resources/input_list.js +++ b/ash/webui/diagnostics_ui/resources/input_list.js
@@ -10,6 +10,7 @@ import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {DiagnosticsBrowserProxy, DiagnosticsBrowserProxyImpl} from './diagnostics_browser_proxy.js'; import {ConnectedDevicesObserverInterface, ConnectedDevicesObserverReceiver, InputDataProviderInterface, KeyboardInfo, TouchDeviceInfo, TouchDeviceType} from './diagnostics_types.js'; import {getInputDataProvider} from './mojo_interface_provider.js'; @@ -25,6 +26,9 @@ behaviors: [I18nBehavior], + /** @private {?DiagnosticsBrowserProxy} */ + browserProxy_: null, + /** @private {?InputDataProviderInterface} */ inputDataProvider_: null, @@ -56,6 +60,8 @@ /** @override */ created() { + this.browserProxy_ = DiagnosticsBrowserProxyImpl.getInstance(); + this.browserProxy_.initialize(); this.inputDataProvider_ = getInputDataProvider(); this.loadInitialDevices_(); this.observeConnectedDevices_(); @@ -148,4 +154,18 @@ this.keyboards_.find((keyboard) => keyboard.id === e.detail.evdevId)); this.keyboardTester_.show(); }, + + /** + * 'navigation-view-panel' is responsible for calling this function when + * the active page changes. + * @param {{isActive: boolean}} isActive + * @public + */ + onNavigationPageChanged({isActive}) { + if (isActive) { + // TODO(ashleydp): Remove when a call can be made at a higher component + // to avoid duplicate code in all navigatable pages. + this.browserProxy_.recordNavigation('input'); + } + }, });
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn index df4a0bf..380766a3 100644 --- a/ash/webui/personalization_app/resources/BUILD.gn +++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -52,6 +52,7 @@ "trusted/user/user_state.ts", "trusted/user/webcam_utils_proxy.ts", "trusted/utils.ts", + "trusted/wallpaper/google_photos_metrics_logger.ts", "trusted/wallpaper/wallpaper_actions.ts", "trusted/wallpaper/untrusted_message_handler.ts", "trusted/wallpaper/wallpaper_controller.ts", @@ -185,6 +186,8 @@ in_files = ts_files + css_wrapper_files + html_wrapper_files + [ "trusted/personalization_app.mojom-webui.js" ] + definitions = [ "//tools/typescript/definitions/metrics_private.d.ts" ] + deps = [ "//third_party/polymer/v3_0:library", "//ui/webui/resources:library",
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_metrics_logger.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_metrics_logger.ts new file mode 100644 index 0000000..6e633ed --- /dev/null +++ b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_metrics_logger.ts
@@ -0,0 +1,34 @@ +// Copyright 2022 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 {assert} from 'chrome://resources/js/assert.m.js'; + +/** + * This enum is tied directly to a UMA enum defined in + * //tools/metrics/histograms/enums.xml and should always reflect it (do not + * change one without changing the other). + * These values are persisted to logs. Entries should not be renumbered and + * numeric values should never be reused. + */ +export enum WallpaperGooglePhotosSource { + Photos = 0, + Albums = 1, + NumSources = 2, +} + +const WallpaperGooglePhotosSourceHistogramName: string = + 'Ash.Wallpaper.GooglePhotos.Source'; + +/** + * Records the section of the Wallpaper app from which a new Google Photos + * wallpaper is selected. + */ +export function recordWallpaperGooglePhotosSourceUMA( + source: WallpaperGooglePhotosSource) { + assert(source < WallpaperGooglePhotosSource.NumSources); + + chrome.metricsPrivate.recordEnumerationValue( + WallpaperGooglePhotosSourceHistogramName, source, + WallpaperGooglePhotosSource.NumSources); +}
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts index 8aeada7..cc934eb 100644 --- a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts +++ b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts
@@ -23,6 +23,7 @@ import {WithPersonalizationStore} from '../personalization_store.js'; import {isGooglePhotosPhoto} from '../utils.js'; +import {recordWallpaperGooglePhotosSourceUMA, WallpaperGooglePhotosSource} from './google_photos_metrics_logger.js'; import {getTemplate} from './google_photos_photos_by_album_id_element.html.js'; import {fetchGooglePhotosAlbum, selectWallpaper} from './wallpaper_controller.js'; import {getWallpaperProvider} from './wallpaper_interface_provider.js'; @@ -230,6 +231,7 @@ assert(e.model.photo); if (!this.isPhotoPlaceholder_(e.model.photo) && isSelectionEvent(e)) { selectWallpaper(e.model.photo, this.wallpaperProvider_, this.getStore()); + recordWallpaperGooglePhotosSourceUMA(WallpaperGooglePhotosSource.Albums); } }
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts index 008d363..2abc6582 100644 --- a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts +++ b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts
@@ -22,6 +22,7 @@ import {WithPersonalizationStore} from '../personalization_store.js'; import {isGooglePhotosPhoto} from '../utils.js'; +import {recordWallpaperGooglePhotosSourceUMA, WallpaperGooglePhotosSource} from './google_photos_metrics_logger.js'; import {getTemplate} from './google_photos_photos_element.html.js'; import {fetchGooglePhotosPhotos, selectWallpaper} from './wallpaper_controller.js'; import {getWallpaperProvider} from './wallpaper_interface_provider.js'; @@ -242,6 +243,7 @@ assert(e.model.photo); if (isSelectionEvent(e)) { selectWallpaper(e.model.photo, this.wallpaperProvider_, this.getStore()); + recordWallpaperGooglePhotosSourceUMA(WallpaperGooglePhotosSource.Photos); } }
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.cc b/ash/webui/shimless_rma/backend/shimless_rma_service.cc index 0b5bff7..69977214 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
@@ -706,6 +706,11 @@ rmad::RmadErrorCode::RMAD_ERROR_REQUEST_INVALID); return; } + + // Clear the previous calibration progress. + last_calibration_progress_ = absl::nullopt; + last_calibration_overall_progress_ = absl::nullopt; + TransitionNextStateGeneric(std::move(callback)); } @@ -831,6 +836,18 @@ std::move(callback).Run(response->log(), response->error()); } +void ShimlessRmaService::GetPowerwashRequired( + GetPowerwashRequiredCallback callback) { + if (state_proto_.state_case() != rmad::RmadState::kRepairComplete) { + LOG(ERROR) << "GetPowerwashRequired called from incorrect state " + << state_proto_.state_case(); + std::move(callback).Run(false); + return; + } + + std::move(callback).Run(state_proto_.repair_complete().powerwash_required()); +} + void ShimlessRmaService::LaunchDiagnostics() { if (state_proto_.state_case() != rmad::RmadState::kRepairComplete) { LOG(ERROR) << "LaunchDiagnostics called from incorrect state " @@ -977,6 +994,10 @@ void ShimlessRmaService::ObserveCalibrationProgress( ::mojo::PendingRemote<mojom::CalibrationObserver> observer) { + if (calibration_observer_.is_bound()) { + calibration_observer_.reset(); + } + calibration_observer_.Bind(std::move(observer)); if (last_calibration_progress_) { calibration_observer_->OnCalibrationUpdated(*last_calibration_progress_);
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.h b/ash/webui/shimless_rma/backend/shimless_rma_service.h index f909a85..c9161285 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service.h +++ b/ash/webui/shimless_rma/backend/shimless_rma_service.h
@@ -130,6 +130,7 @@ WriteProtectManuallyEnabledCallback callback) override; void GetLog(GetLogCallback callback) override; + void GetPowerwashRequired(GetPowerwashRequiredCallback callback) override; void LaunchDiagnostics() override; void EndRmaAndReboot(EndRmaAndRebootCallback callback) override; void EndRmaAndShutdown(EndRmaAndShutdownCallback callback) override;
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc index 4b31679e..caba016 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
@@ -2625,6 +2625,31 @@ run_loop.RunUntilIdle(); } +TEST_F(ShimlessRmaServiceTest, GetPowerwashRequired) { + rmad::GetStateReply repair_complete_state = + CreateStateReply(rmad::RmadState::kRepairComplete, rmad::RMAD_ERROR_OK); + repair_complete_state.mutable_state() + ->mutable_repair_complete() + ->set_powerwash_required(true); + const std::vector<rmad::GetStateReply> fake_states = {repair_complete_state}; + fake_rmad_client_()->SetFakeStateReplies(std::move(fake_states)); + base::RunLoop run_loop; + shimless_rma_provider_->GetCurrentState(base::BindLambdaForTesting( + [&](mojom::State state, bool can_cancel, bool can_go_back, + rmad::RmadErrorCode error) { + EXPECT_EQ(state, mojom::State::kRepairComplete); + EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK); + })); + run_loop.RunUntilIdle(); + + shimless_rma_provider_->GetPowerwashRequired( + base::BindLambdaForTesting([&](const bool powerwash_required) { + EXPECT_EQ(powerwash_required, true); + run_loop.Quit(); + })); + run_loop.Run(); +} + TEST_F(ShimlessRmaServiceTest, EndRmaAndReboot) { const std::vector<rmad::GetStateReply> fake_states = { CreateStateReply(rmad::RmadState::kRepairComplete, rmad::RMAD_ERROR_OK), @@ -2865,16 +2890,38 @@ overall_observations.push_back(status); } + mojo::PendingRemote<mojom::CalibrationObserver> GenerateRemote() { + if (receiver.is_bound()) + receiver.reset(); + + mojo::PendingRemote<mojom::CalibrationObserver> remote; + receiver.Bind(remote.InitWithNewPipeAndPassReceiver()); + return remote; + } + std::vector<rmad::CalibrationComponentStatus> component_observations; std::vector<rmad::CalibrationOverallStatus> overall_observations; mojo::Receiver<mojom::CalibrationObserver> receiver{this}; }; TEST_F(ShimlessRmaServiceTest, ObserveCalibration) { + const std::vector<rmad::GetStateReply> fake_states = { + CreateStateReply(rmad::RmadState::kSetupCalibration, rmad::RMAD_ERROR_OK), + CreateStateReply(rmad::RmadState::kRunCalibration, rmad::RMAD_ERROR_OK)}; + fake_rmad_client_()->SetFakeStateReplies(std::move(fake_states)); + + base::RunLoop run_loop; + shimless_rma_provider_->GetCurrentState(base::BindLambdaForTesting( + [&](mojom::State state, bool can_cancel, bool can_go_back, + rmad::RmadErrorCode error) { + EXPECT_EQ(state, mojom::State::kSetupCalibration); + EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK); + })); + run_loop.RunUntilIdle(); + FakeCalibrationObserver fake_observer; shimless_rma_provider_->ObserveCalibrationProgress( - fake_observer.receiver.BindNewPipeAndPassRemote()); - base::RunLoop run_loop; + fake_observer.GenerateRemote()); fake_rmad_client_()->TriggerCalibrationProgressObservation( rmad::RmadComponent::RMAD_COMPONENT_BASE_ACCELEROMETER, rmad::CalibrationComponentStatus::RMAD_CALIBRATION_IN_PROGRESS, 0.25); @@ -2885,6 +2932,28 @@ EXPECT_EQ(fake_observer.component_observations[0].status(), rmad::CalibrationComponentStatus::RMAD_CALIBRATION_IN_PROGRESS); EXPECT_EQ(fake_observer.component_observations[0].progress(), 0.25); + + shimless_rma_provider_->RunCalibrationStep(base::BindLambdaForTesting( + [&](mojom::State state, bool can_cancel, bool can_go_back, + rmad::RmadErrorCode error) { + EXPECT_EQ(state, mojom::State::kRunCalibration); + EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK); + })); + + // Simulate returning to the calibration run page and observing a new + // calibration. + shimless_rma_provider_->ObserveCalibrationProgress( + fake_observer.GenerateRemote()); + fake_rmad_client_()->TriggerCalibrationProgressObservation( + rmad::RmadComponent::RMAD_COMPONENT_BASE_GYROSCOPE, + rmad::CalibrationComponentStatus::RMAD_CALIBRATION_COMPLETE, 1.0); + run_loop.RunUntilIdle(); + EXPECT_EQ(fake_observer.component_observations.size(), 2UL); + EXPECT_EQ(fake_observer.component_observations[1].component(), + rmad::RmadComponent::RMAD_COMPONENT_BASE_GYROSCOPE); + EXPECT_EQ(fake_observer.component_observations[1].status(), + rmad::CalibrationComponentStatus::RMAD_CALIBRATION_COMPLETE); + EXPECT_EQ(fake_observer.component_observations[1].progress(), 1.0); } TEST_F(ShimlessRmaServiceTest, ObserveCalibrationAfterSignal) {
diff --git a/ash/webui/shimless_rma/mojom/shimless_rma.mojom b/ash/webui/shimless_rma/mojom/shimless_rma.mojom index f1fbe662..aae02e1 100644 --- a/ash/webui/shimless_rma/mojom/shimless_rma.mojom +++ b/ash/webui/shimless_rma/mojom/shimless_rma.mojom
@@ -741,6 +741,8 @@ // Get the RMA Log. // Returns an error indicating success or a failure. GetLog() => (string log, RmadErrorCode error); + // Get whether need to powerwash at the end of repair. + GetPowerwashRequired() => (bool powerwash_required); // Launch the system diagnostics app. LaunchDiagnostics(); // Complete RMA and reboot.
diff --git a/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js b/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js index 6032b28..10dcd22 100644 --- a/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js +++ b/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js
@@ -706,6 +706,18 @@ this.methods_.setResult('getLog', {log: log, error: RmadErrorCode.kOk}); } + /** @return {!Promise<{powerwashRequired: boolean, error: !RmadErrorCode}>} */ + getPowerwashRequired() { + return this.methods_.resolveMethod('getPowerwashRequired'); + } + + /** @param {boolean} powerwashRequired */ + setGetPowerwashRequiredResult(powerwashRequired) { + this.methods_.setResult( + 'getPowerwashRequired', + {powerwashRequired: powerwashRequired, error: RmadErrorCode.kOk}); + } + launchDiagnostics() { console.log('(Fake) Launching diagnostics...'); } @@ -1270,6 +1282,7 @@ this.methods_.register('writeProtectManuallyEnabled'); this.methods_.register('getLog'); + this.methods_.register('getPowerwashRequired'); this.methods_.register('endRmaAndReboot'); this.methods_.register('endRmaAndShutdown'); this.methods_.register('endRmaAndCutoffBattery');
diff --git a/ash/webui/shimless_rma/resources/mojo_interface_provider.js b/ash/webui/shimless_rma/resources/mojo_interface_provider.js index beda46e..768a9def 100644 --- a/ash/webui/shimless_rma/resources/mojo_interface_provider.js +++ b/ash/webui/shimless_rma/resources/mojo_interface_provider.js
@@ -86,6 +86,7 @@ service.automaticallyTriggerPowerCableStateObservation(); service.setGetLogResult(fakeLog); + service.setGetPowerwashRequiredResult(true); // Set the fake service. setShimlessRmaServiceForTesting(service);
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h index 321329d..d69c000 100644 --- a/base/memory/raw_ptr.h +++ b/base/memory/raw_ptr.h
@@ -891,12 +891,24 @@ // during the free operation, which will lead to taking the slower path that // involves quarantine. RAW_PTR_FUNC_ATTRIBUTES void ClearAndDelete() noexcept { +#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) + // We cannot directly `delete` a wrapped pointer, since the tag bits + // atop will lead PA totally astray. + T* ptr = Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_); +#else T* ptr = wrapped_ptr_; +#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) operator=(nullptr); delete ptr; } RAW_PTR_FUNC_ATTRIBUTES void ClearAndDeleteArray() noexcept { +#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) + // We cannot directly `delete` a wrapped pointer, since the tag bits + // atop will lead PA totally astray. + T* ptr = Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_); +#else T* ptr = wrapped_ptr_; +#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) operator=(nullptr); delete[] ptr; }
diff --git a/base/memory/raw_ptr_unittest.cc b/base/memory/raw_ptr_unittest.cc index cf79fa1..2811586 100644 --- a/base/memory/raw_ptr_unittest.cc +++ b/base/memory/raw_ptr_unittest.cc
@@ -96,6 +96,9 @@ #if BUILDFLAG(USE_BACKUP_REF_PTR) using CountingSuperClass = base::internal::BackupRefPtrImpl</*AllowDangling=*/false>; +#elif defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) +using CountingSuperClass = base::internal::MTECheckedPtrImpl< + base::internal::MTECheckedPtrImplPartitionAllocSupport>; #else using CountingSuperClass = base::internal::RawPtrNoOpImpl; #endif @@ -288,7 +291,12 @@ EXPECT_EQ(g_wrap_raw_ptr_cnt, 1); EXPECT_EQ(g_release_wrapped_ptr_cnt, 1); EXPECT_EQ(g_get_for_dereference_cnt, 0); +#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) + // When `MTECheckedPtr` is active, we must unwrap to delete. + EXPECT_EQ(g_get_for_extraction_cnt, 1); +#else EXPECT_EQ(g_get_for_extraction_cnt, 0); +#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) EXPECT_EQ(g_wrapped_ptr_swap_cnt, 0); EXPECT_EQ(ptr.get(), nullptr); } @@ -299,7 +307,12 @@ EXPECT_EQ(g_wrap_raw_ptr_cnt, 1); EXPECT_EQ(g_release_wrapped_ptr_cnt, 1); EXPECT_EQ(g_get_for_dereference_cnt, 0); +#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) + // When `MTECheckedPtr` is active, we must unwrap to delete. + EXPECT_EQ(g_get_for_extraction_cnt, 1); +#else EXPECT_EQ(g_get_for_extraction_cnt, 0); +#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) EXPECT_EQ(g_wrapped_ptr_swap_cnt, 0); EXPECT_EQ(ptr.get(), nullptr); }
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h index f1ce480..d869c89 100644 --- a/base/process/process_metrics.h +++ b/base/process/process_metrics.h
@@ -267,12 +267,6 @@ TimeDelta last_cumulative_cpu_; #endif - // Used to store the previous times and disk usage counts so we can - // compute the disk usage between calls. - TimeTicks last_disk_usage_time_; - // Number of bytes transferred to/from disk in bytes. - uint64_t last_cumulative_disk_usage_ = 0; - #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ BUILDFLAG(IS_AIX) // Same thing for idle wakeups.
diff --git a/base/win/embedded_i18n/generate_embedded_i18n.gni b/base/win/embedded_i18n/generate_embedded_i18n.gni index 0e2c18c..08da8f8d 100644 --- a/base/win/embedded_i18n/generate_embedded_i18n.gni +++ b/base/win/embedded_i18n/generate_embedded_i18n.gni
@@ -59,14 +59,6 @@ [ "iw", "no", - - # TODO(b/192306364): Welsh is temporarily added - # in as a XTB translation without any outputs. - # This should be moved to all_chrome_locales, - # but doing so will be non-trivial as it is the - # first locale in all_chrome_locale which is - # not built for Android. - "cy", ] - pseudolocales template("generate_embedded_i18n") {
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index ec4cd03..3d8478ac2 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -404,7 +404,7 @@ # Mapping files generated by R8 include comments that may break # some of our tooling so remove those (specifically: apkanalyzer). out_file.writelines(l for l in in_file if not l.startswith('#')) - return base_context + return split_contexts_by_name def _OutputKeepRules(r8_path, input_paths, classpath, targets_re_string, @@ -481,8 +481,8 @@ stderr = build_utils.FilterLines( stderr, '|'.join(re.escape(x) for x in ignored_lines)) if stderr: - if ' ' in stderr: - stderr = error_title + """ + if 'Missing' in stderr: + stderr = 'TraceReferences failed: ' + error_title + """ Tip: Build with: is_java_debug=false treat_warnings_as_errors=false @@ -505,7 +505,6 @@ stderr = '' return stderr - logging.debug('cmd: %s', ' '.join(cmd)) build_utils.CheckOutput(cmd, print_stdout=True, stderr_filter=stderr_filter, @@ -605,6 +604,47 @@ build_utils.WriteDepfile(options.depfile, output, inputs=inputs) +def _IterParentContexts(context_name, split_contexts_by_name): + while context_name: + context = split_contexts_by_name[context_name] + yield context + context_name = context.parent_name + + +def _DoTraceReferencesChecks(options, split_contexts_by_name): + # Set of all contexts that are a parent to another. + parent_splits_context_names = { + c.parent_name + for c in split_contexts_by_name.values() if c.parent_name + } + context_sets = [ + list(_IterParentContexts(n, split_contexts_by_name)) + for n in parent_splits_context_names + ] + # Visit them in order of: base, base+chrome, base+chrome+thing. + context_sets.sort(key=lambda x: (len(x), x[0].name)) + + # Ensure there are no missing references when considering all dex files. + error_title = 'DEX contains references to non-existent symbols after R8.' + dex_files = sorted(c.final_output_path + for c in split_contexts_by_name.values()) + _CheckForMissingSymbols(options.r8_path, dex_files, options.classpath, + options.warnings_as_errors, error_title) + + for context_set in context_sets: + # Ensure there are no references from base -> chrome module, or from + # chrome -> feature modules. + error_title = (f'DEX within module "{context_set[0].name}" contains ' + 'reference(s) to symbols within child splits') + dex_files = [c.final_output_path for c in context_set] + # Each check currently takes about 3 seconds on a fast dev machine, and we + # run 3 of them (all, base, base+chrome). + # We could run them concurrently, to shave off 5-6 seconds, but would need + # to make sure that the order is maintained. + _CheckForMissingSymbols(options.r8_path, dex_files, options.classpath, + options.warnings_as_errors, error_title) + + def main(): build_utils.InitLogging('PROGUARD_DEBUG') options = _ParseOptions() @@ -653,27 +693,12 @@ options.keep_rules_output_path) return - base_context = _OptimizeWithR8(options, proguard_configs, libraries, - dynamic_config_data, print_stdout) + split_contexts_by_name = _OptimizeWithR8(options, proguard_configs, libraries, + dynamic_config_data, print_stdout) if not options.disable_checks: logging.debug('Running tracereferences') - all_dex_files = [] - if options.output_path: - all_dex_files.append(options.output_path) - if options.dex_dests: - all_dex_files.extend(options.dex_dests) - error_title = 'DEX contains references to non-existent symbols after R8.' - _CheckForMissingSymbols(options.r8_path, all_dex_files, options.classpath, - options.warnings_as_errors, error_title) - # Also ensure that base module doesn't have any references to child dex - # symbols. - # TODO(agrieve): Remove this check once r8 desugaring is fixed to not put - # synthesized classes in the base module. - error_title = 'Base module DEX contains references symbols within DFMs.' - _CheckForMissingSymbols(options.r8_path, [base_context.final_output_path], - options.classpath, options.warnings_as_errors, - error_title) + _DoTraceReferencesChecks(options, split_contexts_by_name) for output in options.extra_mapping_output_paths: shutil.copy(options.mapping_output, output)
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index 590bfc5..33b61374f 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni
@@ -30,7 +30,7 @@ declare_args() { # Set to true to use the android unwinder V2 implementation. - use_android_unwinder_v2 = false + use_android_unwinder_v2 = true # If this running on a GPU FYI bot. # TODO(https://crbug.com/1233871): Remove this again.
diff --git a/build/config/fuchsia/test/web_engine_required_capabilities.test-cmx b/build/config/fuchsia/test/web_engine_required_capabilities.test-cmx index c512899..5f56800 100644 --- a/build/config/fuchsia/test/web_engine_required_capabilities.test-cmx +++ b/build/config/fuchsia/test/web_engine_required_capabilities.test-cmx
@@ -3,14 +3,15 @@ "fuchsia.test": { "injected-services": { "fuchsia.fonts.Provider": "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx", + "fuchsia.hardware.display.Provider": "fuchsia-pkg://fuchsia.com/fake-hardware-display-controller-provider#meta/hdcp.cmx", "fuchsia.memorypressure.Provider": "fuchsia-pkg://fuchsia.com/memory_monitor#meta/memory_monitor.cmx", + "fuchsia.ui.scenic.Scenic": "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx", "fuchsia.web.ContextProvider": "fuchsia-pkg://fuchsia.com/web_engine#meta/context_provider.cmx", }, "system-services": [ "fuchsia.device.NameProvider", "fuchsia.scheduler.ProfileProvider", "fuchsia.sysmem.Allocator", - "fuchsia.ui.scenic.Scenic" ] } },
diff --git a/build/config/locales.gni b/build/config/locales.gni index 6088761..9f64ecda 100644 --- a/build/config/locales.gni +++ b/build/config/locales.gni
@@ -36,6 +36,7 @@ "bs", "ca", "cs", + "cy", "da", "de", "el", @@ -151,7 +152,9 @@ ] # Setup |platform_pak_locales| for each platform. -platform_pak_locales = all_chrome_locales +# Welsh is currently excluded as it is not included in any platform's build. +# TODO(b/192306364): Add Welsh to CrOS only. +platform_pak_locales = all_chrome_locales - [ "cy" ] if (!is_android) { platform_pak_locales -= extended_locales }
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh index 47aa31d..260373a 100755 --- a/build/install-build-deps.sh +++ b/build/install-build-deps.sh
@@ -386,6 +386,26 @@ if package_exists python-yaml; then backwards_compatible_list="${backwards_compatible_list} python-yaml" fi +if package_exists apache2.2-bin; then + backwards_compatible_list="${backwards_compatible_list} apache2.2-bin" +else + backwards_compatible_list="${backwards_compatible_list} apache2-bin" +fi +if package_exists php7.4-cgi; then + backwards_compatible_list="${backwards_compatible_list} php7.4-cgi libapache2-mod-php7.4" +elif package_exists php7.3-cgi; then + backwards_compatible_list="${backwards_compatible_list} php7.3-cgi libapache2-mod-php7.3" +elif package_exists php7.2-cgi; then + backwards_compatible_list="${backwards_compatible_list} php7.2-cgi libapache2-mod-php7.2" +elif package_exists php7.1-cgi; then + backwards_compatible_list="${backwards_compatible_list} php7.1-cgi libapache2-mod-php7.1" +elif package_exists php7.0-cgi; then + backwards_compatible_list="${backwards_compatible_list} php7.0-cgi libapache2-mod-php7.0" +elif package_exists php8.0-cgi; then + backwards_compatible_list="${backwards_compatible_list} php8.0-cgi libapache2-mod-php8.0" +else + backwards_compatible_list="${backwards_compatible_list} php5-cgi libapache2-mod-php5" +fi case $distro_codename in trusty) @@ -515,29 +535,9 @@ else dev_list="${dev_list} libbrlapi0.5" fi -if package_exists apache2.2-bin; then - dev_list="${dev_list} apache2.2-bin" -else - dev_list="${dev_list} apache2-bin" -fi if package_exists libav-tools; then dev_list="${dev_list} libav-tools" fi -if package_exists php7.4-cgi; then - dev_list="${dev_list} php7.4-cgi libapache2-mod-php7.4" -elif package_exists php7.3-cgi; then - dev_list="${dev_list} php7.3-cgi libapache2-mod-php7.3" -elif package_exists php7.2-cgi; then - dev_list="${dev_list} php7.2-cgi libapache2-mod-php7.2" -elif package_exists php7.1-cgi; then - dev_list="${dev_list} php7.1-cgi libapache2-mod-php7.1" -elif package_exists php7.0-cgi; then - dev_list="${dev_list} php7.0-cgi libapache2-mod-php7.0" -elif package_exists php8.0-cgi; then - dev_list="${dev_list} php8.0-cgi libapache2-mod-php8.0" -else - dev_list="${dev_list} php5-cgi libapache2-mod-php5" -fi # Some packages are only needed if the distribution actually supports # installing them.
diff --git a/build/skia_gold_common/skia_gold_properties.py b/build/skia_gold_common/skia_gold_properties.py index f4a0d4995..9f3f722 100644 --- a/build/skia_gold_common/skia_gold_properties.py +++ b/build/skia_gold_common/skia_gold_properties.py
@@ -111,6 +111,31 @@ 'Automatically determined that test is running on a bot') return self._local_pixel_tests + @staticmethod + def AddCommandLineArguments(parser): + """ Add command line arguments to an ArgumentParser instance + + Args: + parser: ArgumentParser instance + + Returns: + None + """ + parser.add_argument('--git-revision', type=str, help='Git revision') + parser.add_argument('--gerrit-issue', type=int, help='Gerrit issue number') + parser.add_argument('--gerrit-patchset', + type=int, + help='Gerrit patchset number') + parser.add_argument('--buildbucket-id', + type=int, + help='Buildbucket ID of builder') + parser.add_argument('--code-review-system', + type=str, + help='Code review system') + parser.add_argument('--continuous-integration-system', + type=str, + help='Continuous integration system') + def _InitializeProperties(self, args): if hasattr(args, 'local_pixel_tests'): # If not set, will be automatically determined later if needed.
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index 53b51fb..dd820068 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -15,6 +15,7 @@ import("//chrome/android/features/dev_ui/dev_ui_module.gni") import("//chrome/android/modules/chrome_bundle_tmpl.gni") import("//chrome/common/features.gni") +import("//components/optimization_guide/features.gni") import("//device/vr/buildflags/buildflags.gni") import("//weblayer/variables.gni") import("channel.gni") @@ -295,6 +296,23 @@ load_library_from_apk = chromium_linker_supported } } + if (build_with_internal_optimization_guide) { + _is_trichrome_3264 = + !_is_trichrome || !android_64bit_target_cpu || _is_64_bit_browser + + if (_is_trichrome_3264) { + deps += [ "//components/optimization_guide/internal:optimization_guide_internal" ] + loadable_modules += + [ "$root_out_dir/liboptimization_guide_internal.so" ] + } else { + _secondary_optimization_guide = "//components/optimization_guide/internal:optimization_guide_internal($android_secondary_abi_toolchain)" + deps += [ _secondary_optimization_guide ] + _secondary_out_dir = + get_label_info(_secondary_optimization_guide, "root_out_dir") + secondary_abi_loadable_modules += + [ "$_secondary_out_dir/liboptimization_guide_internal.so" ] + } + } if (_target_type == "android_apk") { command_line_flags_file = "chrome-command-line" }
diff --git a/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected b/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected index 0392570..aec0fe97 100644 --- a/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected +++ b/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected
@@ -1,6 +1,7 @@ apk_path=lib/arm64-v8a/crazy.libchrome.so, compress=False, alignment=4096 apk_path=lib/arm64-v8a/libchrome_crashpad_handler.so, compress=True, alignment=0 apk_path=lib/arm64-v8a/libchromium_android_linker.so, compress=True, alignment=0 +apk_path=lib/arm64-v8a/liboptimization_guide_internal.so, compress=False, alignment=4096 apk_path=assets/chrome_100_percent.pak, compress=False, alignment=4 apk_path=assets/icudtl.dat, compress=False, alignment=4 apk_path=assets/locales/af.pak, compress=False, alignment=4
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java index c8e6372d..36a5c08 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
@@ -72,7 +72,7 @@ } if (mInstallDelegate == null) { - notify(WebApkInstallResult.FAILURE); + notify(WebApkInstallResult.NO_INSTALLER); WebApkUmaRecorder.recordGooglePlayInstallResult( WebApkUmaRecorder.GooglePlayInstallResult.FAILED_NO_DELEGATE); return; @@ -125,7 +125,7 @@ private void updateAsync( String packageName, int version, String title, String token) { if (mInstallDelegate == null) { - notify(WebApkInstallResult.FAILURE); + notify(WebApkInstallResult.NO_INSTALLER); return; }
diff --git a/chrome/android/static_initializers.gni b/chrome/android/static_initializers.gni index ced7c4d..b0c2d5e 100644 --- a/chrome/android/static_initializers.gni +++ b/chrome/android/static_initializers.gni
@@ -4,6 +4,7 @@ import("//build/config/features.gni") import("//build/config/sanitizers/sanitizers.gni") +import("//components/optimization_guide/features.gni") import("//ui/gl/features.gni") # The monochrome_static_initializers target will cause release bots to fail if @@ -38,6 +39,12 @@ # base_logging.cc (initializer offset 0x9a4b0c size 0x48) expected_static_initializer_count += 1 + if (build_with_internal_optimization_guide) { + # 000081d1 t _GLOBAL__I_000101 + # 000081dd t _GLOBAL__sub_I_iostream.cpp + expected_static_initializer_count += 2 + } + if (use_static_angle && !is_official_build && (is_debug || dcheck_always_on)) { # TODO(https://crbug.com/1172451): remove global variables from ANGLE:
diff --git a/chrome/app/chrome_dll.rc b/chrome/app/chrome_dll.rc index d299571a..dd09d73 100644 --- a/chrome/app/chrome_dll.rc +++ b/chrome/app/chrome_dll.rc
@@ -86,6 +86,8 @@ "S", IDC_SAVE_PAGE, VIRTKEY, CONTROL "9", IDC_SELECT_LAST_TAB, VIRTKEY, CONTROL VK_NUMPAD9, IDC_SELECT_LAST_TAB, VIRTKEY, CONTROL + VK_NEXT, IDC_MOVE_TAB_NEXT, VIRTKEY, CONTROL, SHIFT + VK_PRIOR, IDC_MOVE_TAB_PREVIOUS, VIRTKEY, CONTROL, SHIFT VK_NEXT, IDC_SELECT_NEXT_TAB, VIRTKEY, CONTROL VK_TAB, IDC_SELECT_NEXT_TAB, VIRTKEY, CONTROL VK_PRIOR, IDC_SELECT_PREVIOUS_TAB, VIRTKEY, CONTROL
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 7db18d67..708bd0d 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -19,6 +19,7 @@ <output filename="chromium_strings_bs.pak" type="data_package" lang="bs" /> <output filename="chromium_strings_ca.pak" type="data_package" lang="ca" /> <output filename="chromium_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="chromium_strings_cy.pak" type="data_package" lang="cy" /> <output filename="chromium_strings_da.pak" type="data_package" lang="da" /> <output filename="chromium_strings_de.pak" type="data_package" lang="de" /> <output filename="chromium_strings_el.pak" type="data_package" lang="el" />
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index dfa4fd5..084d9cb 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -24,6 +24,7 @@ <output filename="generated_resources_bs.pak" type="data_package" lang="bs" /> <output filename="generated_resources_ca.pak" type="data_package" lang="ca" /> <output filename="generated_resources_cs.pak" type="data_package" lang="cs" /> + <output filename="generated_resources_cy.pak" type="data_package" lang="cy" /> <output filename="generated_resources_da.pak" type="data_package" lang="da" /> <output filename="generated_resources_de.pak" type="data_package" lang="de" /> <output filename="generated_resources_el.pak" type="data_package" lang="el" /> @@ -4878,7 +4879,7 @@ Has access to this site </message> <message name="IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON" desc="The text of the request acces button that appears on the toolbar when an extension requests access to the site"> - Allow? + Allow <ph name="EXTENSIONS_REQUESTING_ACCESS_COUNT">$1<ex>3</ex></ph>? </message> <if expr="not use_titlecase"> <message name="IDS_EXTENSIONS_CONTEXT_MENU_CANT_ACCESS_PAGE" desc="The label in an extension's context menu indicating the extension cannot access the current page. (sentence case)">
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON.png.sha1 index 22e6bde..0710855e 100644 --- a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON.png.sha1
@@ -1 +1 @@ -608fcedc3b840c237b27968ce81e3f9ebaee0bb2 \ No newline at end of file +ad553089adedea3971a955ffbd1131a26ee6323f \ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index f517a766..fed710528 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -21,6 +21,7 @@ <output filename="google_chrome_strings_bs.pak" type="data_package" lang="bs" /> <output filename="google_chrome_strings_ca.pak" type="data_package" lang="ca" /> <output filename="google_chrome_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="google_chrome_strings_cy.pak" type="data_package" lang="cy" /> <output filename="google_chrome_strings_da.pak" type="data_package" lang="da" /> <output filename="google_chrome_strings_de.pak" type="data_package" lang="de" /> <output filename="google_chrome_strings_el.pak" type="data_package" lang="el" />
diff --git a/chrome/app/resources/locale_settings.grd b/chrome/app/resources/locale_settings.grd index 24a0a74..5c00a46 100644 --- a/chrome/app/resources/locale_settings.grd +++ b/chrome/app/resources/locale_settings.grd
@@ -15,6 +15,7 @@ <output filename="locale_settings_bs.pak" type="data_package" lang="bs" /> <output filename="locale_settings_ca.pak" type="data_package" lang="ca" /> <output filename="locale_settings_cs.pak" type="data_package" lang="cs" /> + <output filename="locale_settings_cy.pak" type="data_package" lang="cy" /> <output filename="locale_settings_da.pak" type="data_package" lang="da" /> <output filename="locale_settings_de.pak" type="data_package" lang="de" /> <output filename="locale_settings_el.pak" type="data_package" lang="el" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 158bfba..a9c746a 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -5065,8 +5065,6 @@ "fullscreen.h", "policy/browser_signin_policy_handler.cc", "policy/browser_signin_policy_handler.h", - "policy/cloud/user_cloud_policy_manager_builder.cc", - "policy/cloud/user_cloud_policy_manager_builder.h", "policy/cloud/user_policy_signin_service_factory.cc", "policy/cloud/user_policy_signin_service_factory.h", "policy/cloud/user_policy_signin_service_util.cc",
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc index af583f0..8815f1c 100644 --- a/chrome/browser/android/webapk/webapk_install_service.cc +++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -95,7 +95,7 @@ // If the install didn't definitely fail, we don't add a shortcut. This could // happen if Play was busy with another install and this one is still queued // (and hence might succeed in the future). - if (result == webapps::WebApkInstallResult::FAILURE) { + if (result != webapps::WebApkInstallResult::PROBABLE_FAILURE) { if (!web_contents) return;
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc index 88507674..9d738cd 100644 --- a/chrome/browser/android/webapk/webapk_installer.cc +++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -276,6 +276,7 @@ DVLOG(1) << "The WebAPK installation failed."; webapk::TrackInstallEvent(webapk::INSTALL_FAILED); } + webapk::TrackInstallResult(result); } delete this; @@ -318,7 +319,7 @@ task_type_ = INSTALL; if (!server_url_.is_valid()) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::SERVER_URL_INVALID); return; } @@ -347,12 +348,12 @@ std::unique_ptr<webapk::WebApk> proto(new webapk::WebApk); if (!proto->ParseFromString(*serialized_webapk_.get())) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::REQUEST_INVALID); return; } if (!server_url_.is_valid()) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::SERVER_URL_INVALID); return; } @@ -370,7 +371,7 @@ jint status) { SpaceStatus space_status = static_cast<SpaceStatus>(status); if (space_status == SpaceStatus::NOT_ENOUGH_SPACE) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::NOT_ENOUGH_SPACE); return; } @@ -391,7 +392,7 @@ task_type_ = UPDATE; if (!server_url_.is_valid()) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::SERVER_URL_INVALID); return; } @@ -406,7 +407,7 @@ std::unique_ptr<std::string> update_request) { std::unique_ptr<webapk::WebApk> proto(new webapk::WebApk); if (update_request->empty() || !proto->ParseFromString(*update_request)) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::REQUEST_INVALID); return; } @@ -472,14 +473,14 @@ if (!response_body || response_code != net::HTTP_OK) { LOG(WARNING) << base::StringPrintf( "WebAPK server returned response code %d.", response_code); - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::SERVER_ERROR); return; } std::unique_ptr<webapk::WebApkResponse> response(new webapk::WebApkResponse); if (!response_body || !response->ParseFromString(*response_body)) { LOG(WARNING) << "WebAPK server did not return proto."; - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::SERVER_ERROR); return; } @@ -495,7 +496,7 @@ if (token.empty() || response->package_name().empty()) { LOG(WARNING) << "WebAPK server returned incomplete proto."; - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::SERVER_ERROR); return; } @@ -586,7 +587,7 @@ absl::optional<std::map<std::string, webapps::WebApkIconHasher::Icon>> hashes) { if (!hashes) { - OnResult(webapps::WebApkInstallResult::FAILURE); + OnResult(webapps::WebApkInstallResult::ICON_HASHER_ERROR); return; } @@ -658,7 +659,7 @@ timer_.Start( FROM_HERE, base::Milliseconds(webapk_server_timeout_ms_), base::BindOnce(&WebApkInstaller::OnResult, weak_ptr_factory_.GetWeakPtr(), - webapps::WebApkInstallResult::FAILURE)); + webapps::WebApkInstallResult::REQUEST_TIMEOUT)); auto request = std::make_unique<network::ResourceRequest>(); request->url = server_url_;
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc index 0f06292..c848be5 100644 --- a/chrome/browser/android/webapk/webapk_installer_unittest.cc +++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -363,7 +363,7 @@ WebApkInstallerRunner runner; runner.RunInstallWebApk(std::move(installer), web_contents(), DefaultShortcutInfo()); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::NOT_ENOUGH_SPACE, runner.result()); } // Test that installation succeeds when the primary icon is guarded by @@ -390,7 +390,7 @@ WebApkInstallerRunner runner; runner.RunInstallWebApk(CreateDefaultWebApkInstaller(), web_contents(), shortcut_info); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::ICON_HASHER_ERROR, runner.result()); } // Test that installation fails if fetching the bitmap at the best splash icon @@ -403,7 +403,19 @@ WebApkInstallerRunner runner; runner.RunInstallWebApk(CreateDefaultWebApkInstaller(), web_contents(), shortcut_info); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::ICON_HASHER_ERROR, runner.result()); +} + +// Test that installation fails if the WebAPK server url is invalid. +TEST_F(WebApkInstallerTest, CreateWebApkInvalidServerUrl) { + SetWebApkServerUrl(GURL()); + std::unique_ptr<WebApkInstaller> installer( + new TestWebApkInstaller(profile(), SpaceStatus::ENOUGH_SPACE)); + + WebApkInstallerRunner runner; + runner.RunInstallWebApk(std::move(installer), web_contents(), + DefaultShortcutInfo()); + EXPECT_EQ(webapps::WebApkInstallResult::SERVER_URL_INVALID, runner.result()); } // Test that installation fails if the WebAPK creation request times out. @@ -416,7 +428,7 @@ WebApkInstallerRunner runner; runner.RunInstallWebApk(std::move(installer), web_contents(), DefaultShortcutInfo()); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::REQUEST_TIMEOUT, runner.result()); } // InstallForService tests @@ -448,7 +460,7 @@ runner.RunInstallForService(std::move(installer), std::move(serialized_proto), shortcut_info.short_name, shortcut_info.source); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::NOT_ENOUGH_SPACE, runner.result()); } // Test installation for service failing if serialized apk invalid. @@ -465,7 +477,7 @@ std::make_unique<std::string>(invalid_serialized_webapk), shortcut_info.short_name, shortcut_info.source); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::REQUEST_INVALID, runner.result()); } namespace { @@ -490,7 +502,7 @@ WebApkInstallerRunner runner; runner.RunInstallWebApk(CreateDefaultWebApkInstaller(), web_contents(), DefaultShortcutInfo()); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::SERVER_ERROR, runner.result()); } // Test update succeeding. @@ -533,7 +545,7 @@ WebApkInstallerRunner runner; runner.RunUpdateWebApk(CreateDefaultWebApkInstaller(), update_request_path); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::REQUEST_INVALID, runner.result()); } // Test that an update fails if the "update request path" points to a @@ -548,7 +560,7 @@ WebApkInstallerRunner runner; runner.RunUpdateWebApk(CreateDefaultWebApkInstaller(), update_request_path); - EXPECT_EQ(webapps::WebApkInstallResult::FAILURE, runner.result()); + EXPECT_EQ(webapps::WebApkInstallResult::REQUEST_INVALID, runner.result()); } // Test that StoreUpdateRequestToFile() creates directories if needed when
diff --git a/chrome/browser/android/webapk/webapk_metrics.cc b/chrome/browser/android/webapk/webapk_metrics.cc index 9b31ec3..638d1f29 100644 --- a/chrome/browser/android/webapk/webapk_metrics.cc +++ b/chrome/browser/android/webapk/webapk_metrics.cc
@@ -11,6 +11,7 @@ const char kInstallDurationHistogram[] = "WebApk.Install.InstallDuration"; const char kInstallEventHistogram[] = "WebApk.Install.InstallEvent"; +const char kInstallResultHistogram[] = "WebApk.Install.InstallResult"; void TrackRequestTokenDuration(base::TimeDelta delta, const std::string& webapk_package) { @@ -25,4 +26,8 @@ UMA_HISTOGRAM_ENUMERATION(kInstallEventHistogram, event, INSTALL_EVENT_MAX); } +void TrackInstallResult(webapps::WebApkInstallResult result) { + UMA_HISTOGRAM_ENUMERATION(kInstallResultHistogram, result, + webapps::WebApkInstallResult::RESULT_MAX); +} } // namespace webapk
diff --git a/chrome/browser/android/webapk/webapk_metrics.h b/chrome/browser/android/webapk/webapk_metrics.h index 67d5acd..1e155d6c 100644 --- a/chrome/browser/android/webapk/webapk_metrics.h +++ b/chrome/browser/android/webapk/webapk_metrics.h
@@ -8,6 +8,7 @@ #include <string> #include "base/time/time.h" +#include "components/webapps/browser/android/webapk/webapk_types.h" namespace webapk { @@ -29,6 +30,7 @@ const std::string& webapk_package); void TrackInstallDuration(base::TimeDelta delta); void TrackInstallEvent(InstallEvent event); +void TrackInstallResult(webapps::WebApkInstallResult result); } // namespace webapk
diff --git a/chrome/browser/apps/intent_helper/intent_picker_features.cc b/chrome/browser/apps/intent_helper/intent_picker_features.cc index 763bc20..885e36b 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_features.cc +++ b/chrome/browser/apps/intent_helper/intent_picker_features.cc
@@ -34,7 +34,7 @@ } bool AppIconInIntentChipEnabled() { - return LinkCapturingInfoBarEnabled() && + return LinkCapturingUiUpdateEnabled() && base::FeatureList::IsEnabled(kIntentChipAppIcon); }
diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc index dc2e9d2..2b9b74a 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc +++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
@@ -144,19 +144,18 @@ // for chromeos, this should apply when navigation is not deferred for pwa only // case also when navigation deferred and then resumed -bool MaybeShowIntentPicker(content::NavigationHandle* navigation_handle) { +void MaybeShowIntentPicker(content::NavigationHandle* navigation_handle) { content::WebContents* web_contents = navigation_handle->GetWebContents(); - std::vector<IntentPickerAppInfo> apps = GetAppsForIntentPicker(web_contents); - bool show_intent_icon = !apps.empty(); + auto apps = GetAppsForIntentPicker(web_contents); + IntentPickerTabHelper::FromWebContents(web_contents)->ShowIconForApps(apps); #if BUILDFLAG(IS_CHROMEOS) MaybeShowIntentPickerBubble(navigation_handle, std::move(apps)); #endif // BUILDFLAG(IS_CHROMEOS) - return show_intent_icon; } void MaybeShowIntentPicker(content::WebContents* web_contents) { - std::vector<IntentPickerAppInfo> apps = GetAppsForIntentPicker(web_contents); - IntentPickerTabHelper::SetShouldShowIcon(web_contents, !apps.empty()); + IntentPickerTabHelper::FromWebContents(web_contents) + ->ShowIconForApps(GetAppsForIntentPicker(web_contents)); } void ShowIntentPickerBubble(content::WebContents* web_contents,
diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.h b/chrome/browser/apps/intent_helper/intent_picker_helpers.h index 30bd1e5..67b691f 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_helpers.h +++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.h
@@ -14,14 +14,13 @@ namespace apps { -// Displays the intent picker bubble in the omnibar if the last committed URL +// Displays the intent picker icon in the omnibox if the last committed URL // has corresponding apps that can open the page. -// Returns if the intent icon should be shown. -[[nodiscard]] bool MaybeShowIntentPicker( - content::NavigationHandle* navigation_handle); -// Overload used to check if the intent picker can be displayed, -// only on non Chrome OS devices. -// Also used to recheck after content is reparented. +// On Chrome OS, this may also display the Intent Picker bubble automatically. +void MaybeShowIntentPicker(content::NavigationHandle* navigation_handle); + +// Displays the intent picker icon in the omnibox, based on the last committed +// URL in |web_contents|. void MaybeShowIntentPicker(content::WebContents* web_contents); void ShowIntentPickerBubble(content::WebContents* web_contents,
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn index a779210..b7607084 100644 --- a/chrome/browser/ash/crosapi/BUILD.gn +++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -203,6 +203,7 @@ "//chrome/common:constants", "//chromeos/ash/components/dbus/upstart", "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_browser", + "//chromeos/components/quick_answers/public/cpp:prefs", "//chromeos/components/sensors", "//chromeos/crosapi/cpp", "//chromeos/crosapi/mojom", @@ -224,6 +225,7 @@ "//components/exo", "//components/flags_ui", "//components/keyed_service/content", + "//components/language/core/browser:browser", "//components/metrics", "//components/metrics/structured", "//components/metrics_services_manager:metrics_services_manager",
diff --git a/chrome/browser/ash/crosapi/prefs_ash.cc b/chrome/browser/ash/crosapi/prefs_ash.cc index 08e0ddc..5ddec3b 100644 --- a/chrome/browser/ash/crosapi/prefs_ash.cc +++ b/chrome/browser/ash/crosapi/prefs_ash.cc
@@ -14,7 +14,9 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/pref_names.h" +#include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h" #include "chromeos/crosapi/mojom/prefs.mojom.h" +#include "components/language/core/browser/pref_names.h" #include "components/metrics/metrics_pref_names.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" @@ -23,6 +25,36 @@ namespace crosapi { namespace { +// List of all mojom::PrefPaths associated with profile prefs, and their +// corresponding paths in the prefstore. Initialized on first use. +const std::string& GetProfilePrefNameForPref(mojom::PrefPath path) { + static base::NoDestructor<std::map<mojom::PrefPath, std::string>> + profile_prefpath_to_name( + {{mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled, + ash::prefs::kAccessibilitySpokenFeedbackEnabled}, + {mojom::PrefPath::kQuickAnswersEnabled, + quick_answers::prefs::kQuickAnswersEnabled}, + {mojom::PrefPath::kQuickAnswersConsentStatus, + quick_answers::prefs::kQuickAnswersConsentStatus}, + {mojom::PrefPath::kQuickAnswersDefinitionEnabled, + quick_answers::prefs::kQuickAnswersDefinitionEnabled}, + {mojom::PrefPath::kQuickAnswersTranslationEnabled, + quick_answers::prefs::kQuickAnswersTranslationEnabled}, + {mojom::PrefPath::kQuickAnswersUnitConversionEnabled, + quick_answers::prefs::kQuickAnswersUnitConversionEnabled}, + {mojom::PrefPath::kQuickAnswersNoticeImpressionCount, + quick_answers::prefs::kQuickAnswersNoticeImpressionCount}, + {mojom::PrefPath::kQuickAnswersNoticeImpressionDuration, + quick_answers::prefs::kQuickAnswersNoticeImpressionDuration}, + {mojom::PrefPath::kPreferredLanguages, + language::prefs::kPreferredLanguages}, + {mojom::PrefPath::kApplicationLocale, + language::prefs::kApplicationLocale}}); + auto pref_name = profile_prefpath_to_name->find(path); + DCHECK(pref_name != profile_prefpath_to_name->end()); + return pref_name->second; +} + // List of all mojom::PrefPaths associated with extension controlled prefs, // and their corresponding paths in the prefstore. Initialized on first use. const std::string& GetExtensionPrefNameForPref(mojom::PrefPath path) { @@ -224,13 +256,23 @@ return State{local_state_, &local_state_registrar_, false, metrics::prefs::kMetricsReportingEnabled}; case mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled: + case mojom::PrefPath::kQuickAnswersEnabled: + case mojom::PrefPath::kQuickAnswersConsentStatus: + case mojom::PrefPath::kQuickAnswersDefinitionEnabled: + case mojom::PrefPath::kQuickAnswersTranslationEnabled: + case mojom::PrefPath::kQuickAnswersUnitConversionEnabled: + case mojom::PrefPath::kQuickAnswersNoticeImpressionCount: + case mojom::PrefPath::kQuickAnswersNoticeImpressionDuration: + case mojom::PrefPath::kPreferredLanguages: + case mojom::PrefPath::kApplicationLocale: { if (!profile_prefs_registrar_) { LOG(WARNING) << "Primary profile is not yet initialized"; return absl::nullopt; } + std::string pref_name = GetProfilePrefNameForPref(path); return State{profile_prefs_registrar_->prefs(), - profile_prefs_registrar_.get(), false, - ash::prefs::kAccessibilitySpokenFeedbackEnabled}; + profile_prefs_registrar_.get(), false, pref_name}; + } case mojom::PrefPath::kDeviceSystemWideTracingEnabled: return State{local_state_, &local_state_registrar_, false, ash::prefs::kDeviceSystemWideTracingEnabled};
diff --git a/chrome/browser/ash/notifications/request_system_proxy_credentials_view.cc b/chrome/browser/ash/notifications/request_system_proxy_credentials_view.cc index c4a5b29..e7448c0 100644 --- a/chrome/browser/ash/notifications/request_system_proxy_credentials_view.cc +++ b/chrome/browser/ash/notifications/request_system_proxy_credentials_view.cc
@@ -30,7 +30,10 @@ #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" -#include "ui/views/layout/grid_layout.h" +#include "ui/views/layout/box_layout_view.h" +#include "ui/views/layout/flex_layout.h" +#include "ui/views/layout/table_layout_view.h" +#include "ui/views/view_class_properties.h" #include "ui/views/widget/widget.h" namespace { @@ -111,89 +114,83 @@ ui::DIALOG_BUTTON_OK, l10n_util::GetStringUTF16(IDS_SYSTEM_PROXY_AUTH_DIALOG_OK_BUTTON)); - views::GridLayout* layout = - SetLayoutManager(std::make_unique<views::GridLayout>()); + SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kVertical); - int column_view_set_id = 0; - views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id); - - column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, - 100, views::GridLayout::ColumnSize::kUsePreferred, 0, - 0); - - layout->StartRow(0, column_view_set_id); - auto info_label = std::make_unique<views::Label>(l10n_util::GetStringFUTF16( - IDS_SYSTEM_PROXY_AUTH_DIALOG_TEXT, base::ASCIIToUTF16(GetProxyServer()))); + auto* info_label = AddChildView(std::make_unique<views::Label>( + l10n_util::GetStringFUTF16(IDS_SYSTEM_PROXY_AUTH_DIALOG_TEXT, + base::ASCIIToUTF16(GetProxyServer())))); info_label->SetEnabled(true); info_label->SetTextStyle(views::style::STYLE_PRIMARY); - layout->AddView(std::move(info_label)); + info_label->SetProperty(views::kCrossAxisAlignmentKey, + views::LayoutAlignment::kStart); - layout->StartRow(0, column_view_set_id); - auto info_label_privacy = std::make_unique<views::Label>( - l10n_util::GetStringUTF16(IDS_SYSTEM_PROXY_AUTH_DIALOG_PRIVACY_WARNING)); + auto* info_label_privacy = AddChildView(std::make_unique<views::Label>( + l10n_util::GetStringUTF16(IDS_SYSTEM_PROXY_AUTH_DIALOG_PRIVACY_WARNING))); info_label_privacy->SetEnabled(true); info_label_privacy->SetTextStyle(views::style::STYLE_SECONDARY); - layout->AddView(std::move(info_label_privacy)); + info_label_privacy->SetProperty(views::kCrossAxisAlignmentKey, + views::LayoutAlignment::kStart); - column_view_set_id++; - column_set = layout->AddColumnSet(column_view_set_id); - column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, - views::GridLayout::kFixedSize, - views::GridLayout::ColumnSize::kUsePreferred, 0, 0); + auto* auth_container = + AddChildView(std::make_unique<views::TableLayoutView>()); + auth_container->AddColumn( + views::LayoutAlignment::kStart, views::LayoutAlignment::kStretch, + views::TableLayout::kFixedSize, + views::TableLayout::ColumnSize::kUsePreferred, 0, 0); const int label_padding = provider->GetDistanceMetric(views::DISTANCE_RELATED_LABEL_HORIZONTAL); - column_set->AddPaddingColumn(0, label_padding); - column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1.0, - views::GridLayout::ColumnSize::kUsePreferred, 0, 0); + auth_container->AddPaddingColumn(views::TableLayout::kFixedSize, + label_padding); + auth_container->AddColumn( + views::LayoutAlignment::kStretch, views::LayoutAlignment::kStretch, 1.0f, + views::TableLayout::ColumnSize::kUsePreferred, 0, 0); const int unrelated_vertical_spacing = provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL); - layout->StartRowWithPadding(1.0, column_view_set_id, 0, - unrelated_vertical_spacing); - auto username_label = std::make_unique<views::Label>( - l10n_util::GetStringUTF16(IDS_SYSTEM_PROXY_AUTH_DIALOG_USERNAME_LABEL)); + auth_container->AddPaddingRow(views::TableLayout::kFixedSize, + unrelated_vertical_spacing); + auth_container->AddRows(1, views::TableLayout::kFixedSize); + auto* username_label = auth_container->AddChildView( + std::make_unique<views::Label>(l10n_util::GetStringUTF16( + IDS_SYSTEM_PROXY_AUTH_DIALOG_USERNAME_LABEL))); username_label->SetEnabled(true); - auto username_textfield = std::make_unique<views::Textfield>(); - username_textfield->SetEnabled(true); - username_textfield->SetAssociatedLabel( - layout->AddView(std::move(username_label))); - username_textfield_ = layout->AddView(std::move(username_textfield)); + username_textfield_ = + auth_container->AddChildView(std::make_unique<views::Textfield>()); + username_textfield_->SetEnabled(true); + username_textfield_->SetAssociatedLabel(username_label); const int related_vertical_spacing = provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL); - layout->StartRowWithPadding(1.0, column_view_set_id, 0, - related_vertical_spacing); - auto password_label = std::make_unique<views::Label>( - l10n_util::GetStringUTF16(IDS_SYSTEM_PROXY_AUTH_DIALOG_PASSWORD_LABEL)); + auth_container->AddPaddingRow(views::TableLayout::kFixedSize, + related_vertical_spacing); + auth_container->AddRows(1, views::TableLayout::kFixedSize); + auto* password_label = auth_container->AddChildView( + std::make_unique<views::Label>(l10n_util::GetStringUTF16( + IDS_SYSTEM_PROXY_AUTH_DIALOG_PASSWORD_LABEL))); password_label->SetEnabled(true); - auto password_textfield = std::make_unique<PassphraseTextfield>(); - password_textfield->SetEnabled(true); - password_textfield->SetAssociatedLabel( - layout->AddView(std::move(password_label))); - password_textfield_ = layout->AddView(std::move(password_textfield)); + password_textfield_ = + auth_container->AddChildView(std::make_unique<PassphraseTextfield>()); + password_textfield_->SetEnabled(true); + password_textfield_->SetAssociatedLabel(password_label); + auth_container->AddPaddingRow(views::TableLayout::kFixedSize, + related_vertical_spacing); - column_view_set_id++; - column_set = layout->AddColumnSet(column_view_set_id); - column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, - views::GridLayout::kFixedSize, - views::GridLayout::ColumnSize::kUsePreferred, 0, 0); - column_set->AddPaddingColumn(0, label_padding); - column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, - 1.0, views::GridLayout::ColumnSize::kUsePreferred, 0, - 0); - layout->StartRowWithPadding(1.0, column_view_set_id, 0, - related_vertical_spacing); - auto error_icon = std::make_unique<views::ImageView>(); - const int kIconSize = 18; + auto* error_container = + AddChildView(std::make_unique<views::BoxLayoutView>()); + error_container->SetBetweenChildSpacing(label_padding); + auto* error_icon = + error_container->AddChildView(std::make_unique<views::ImageView>()); + constexpr int kIconSize = 18; error_icon->SetImage(ui::ImageModel::FromVectorIcon( vector_icons::kInfoOutlineIcon, ui::kColorAlertHighSeverity, kIconSize)); error_icon->SetImageSize(gfx::Size(kIconSize, kIconSize)); error_icon->SetVisible(show_error_label_); - layout->AddView(std::move(error_icon)); - error_label_ = - layout->AddView(std::make_unique<ErrorLabelView>(show_error_label_)); + error_label_ = error_container->AddChildView( + std::make_unique<ErrorLabelView>(show_error_label_)); + error_container->SetFlexForView(error_label_, 1); } BEGIN_METADATA(RequestSystemProxyCredentialsView, views::DialogDelegateView)
diff --git a/chrome/browser/ash/system_extensions/BUILD.gn b/chrome/browser/ash/system_extensions/BUILD.gn index 1d06127..ae14e5c 100644 --- a/chrome/browser/ash/system_extensions/BUILD.gn +++ b/chrome/browser/ash/system_extensions/BUILD.gn
@@ -34,10 +34,8 @@ "system_extensions_sandboxed_unpacker.cc", "system_extensions_sandboxed_unpacker.h", "system_extensions_status_or.h", - "system_extensions_ui.cc", - "system_extensions_ui.h", - "system_extensions_web_ui_config_map.cc", - "system_extensions_web_ui_config_map.h", + "system_extensions_webui_config.cc", + "system_extensions_webui_config.h", ] deps = [ ":system_extensions_group",
diff --git a/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc b/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc index a783b7f..385bad9dc 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc +++ b/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc
@@ -19,6 +19,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/navigation_entry.h" +#include "content/public/common/content_features.h" #include "content/public/common/page_type.h" #include "content/public/test/browser_test.h" @@ -41,10 +42,57 @@ return test_dir.Append("system_extensions").Append("basic_system_extension"); } +// Class that returns the result of the first System Extension service worker it +// sees. +class ServiceWorkerRegistrationObserver + : public SystemExtensionsInstallManager::Observer { + public: + explicit ServiceWorkerRegistrationObserver(SystemExtensionsProvider& provider) + : install_manager_(provider.install_manager()) { + install_manager_.AddObserver(this); + } + ~ServiceWorkerRegistrationObserver() override {} + + // Returns the saved result or waits to get a result and returns it. + std::pair<SystemExtensionId, blink::ServiceWorkerStatusCode> + GetIdAndStatusCode() { + if (id_.has_value()) + return {id_.value(), status_code_.value()}; + + run_loop_.Run(); + return {id_.value(), status_code_.value()}; + } + + // SystemExtensionsInstallManager::Observer + void OnServiceWorkerRegistered( + const SystemExtensionId& id, + blink::ServiceWorkerStatusCode status_code) override { + install_manager_.RemoveObserver(this); + + // Should happen because we unregistered as observers. + DCHECK(!id_.has_value()); + + id_ = id; + status_code_ = status_code; + run_loop_.Quit(); + } + + private: + // Should be present for the duration of the test. + SystemExtensionsInstallManager& install_manager_; + + base::RunLoop run_loop_; + absl::optional<SystemExtensionId> id_; + absl::optional<blink::ServiceWorkerStatusCode> status_code_; +}; + class SystemExtensionsBrowserTest : public InProcessBrowserTest { public: SystemExtensionsBrowserTest() { - feature_list_.InitAndEnableFeature(ash::features::kSystemExtensions); + feature_list_.InitWithFeatures( + {ash::features::kSystemExtensions, + features::kEnableServiceWorkersForChromeUntrusted}, + {}); } ~SystemExtensionsBrowserTest() override = default; @@ -105,6 +153,7 @@ auto* provider = SystemExtensionsProvider::Get(browser()->profile()); auto& install_manager = provider->install_manager(); + ServiceWorkerRegistrationObserver sw_registration_observer(*provider); base::RunLoop run_loop; install_manager.InstallUnpackedExtensionFromDir( GetBasicSystemExtensionDir(), @@ -114,6 +163,11 @@ run_loop.Quit(); })); run_loop.Run(); + + const auto [id, status_code] = sw_registration_observer.GetIdAndStatusCode(); + EXPECT_EQ(kTestSystemExtensionId, id); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status_code); + TestInstalledTestExtensionWorks(); }
diff --git a/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc b/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc index 3fb2fdc..b75f14a 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc +++ b/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc
@@ -18,9 +18,16 @@ #include "base/values.h" #include "chrome/browser/ash/system_extensions/system_extension.h" #include "chrome/browser/ash/system_extensions/system_extensions_profile_utils.h" -#include "chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.h" +#include "chrome/browser/ash/system_extensions/system_extensions_webui_config.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" +#include "content/public/browser/service_worker_context.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/browser/webui_config_map.h" #include "content/public/common/url_constants.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_registration_options.mojom.h" #include "url/gurl.h" #include "url/origin.h" @@ -124,10 +131,50 @@ } SystemExtensionId id = system_extension.id; - SystemExtensionsWebUIConfigMap::GetInstance().AddForSystemExtension( - system_extension); + auto config = std::make_unique<SystemExtensionsWebUIConfig>(system_extension); + content::WebUIConfigMap::GetInstance().AddUntrustedWebUIConfig( + std::move(config)); + system_extensions_[{1, 2, 3, 4}] = std::move(system_extension); std::move(final_callback).Run(std::move(id)); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&SystemExtensionsInstallManager::RegisterServiceWorker, + weak_ptr_factory_.GetWeakPtr(), id)); +} + +void SystemExtensionsInstallManager::RegisterServiceWorker( + const SystemExtensionId& system_extension_id) { + auto it = system_extensions_.find(system_extension_id); + if (it == system_extensions_.end()) { + LOG(ERROR) << "Tried to install service worker for non-existent extension"; + return; + } + + const SystemExtension& system_extension = it->second; + + blink::mojom::ServiceWorkerRegistrationOptions options( + system_extension.base_url, blink::mojom::ScriptType::kClassic, + blink::mojom::ServiceWorkerUpdateViaCache::kImports); + blink::StorageKey key(url::Origin::Create(options.scope)); + + auto* worker_context = + profile_->GetDefaultStoragePartition()->GetServiceWorkerContext(); + worker_context->RegisterServiceWorker( + system_extension.service_worker_url, key, options, + base::BindOnce(&SystemExtensionsInstallManager::OnRegisterServiceWorker, + weak_ptr_factory_.GetWeakPtr(), system_extension_id)); +} + +void SystemExtensionsInstallManager::OnRegisterServiceWorker( + const SystemExtensionId& system_extension_id, + blink::ServiceWorkerStatusCode status_code) { + if (status_code != blink::ServiceWorkerStatusCode::kOk) + LOG(ERROR) << "Failed to register Service Worker: " + << blink::ServiceWorkerStatusToString(status_code); + + for (auto& observer : observers_) + observer.OnServiceWorkerRegistered(system_extension_id, status_code); } bool SystemExtensionsInstallManager::IOHelper::CopyExtensionAssets(
diff --git a/chrome/browser/ash/system_extensions/system_extensions_install_manager.h b/chrome/browser/ash/system_extensions/system_extensions_install_manager.h index 7919ac31..e6596ba 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_install_manager.h +++ b/chrome/browser/ash/system_extensions/system_extensions_install_manager.h
@@ -9,16 +9,25 @@ #include "base/files/file_path.h" #include "base/memory/weak_ptr.h" +#include "base/observer_list.h" #include "base/one_shot_event.h" #include "base/task/thread_pool.h" #include "base/threading/sequence_bound.h" #include "chrome/browser/ash/system_extensions/system_extensions_install_status.h" #include "chrome/browser/ash/system_extensions/system_extensions_sandboxed_unpacker.h" +#include "third_party/blink/public/common/service_worker/service_worker_status_code.h" class Profile; class SystemExtensionsInstallManager { public: + class Observer : public base::CheckedObserver { + public: + virtual void OnServiceWorkerRegistered( + const SystemExtensionId& system_extension_id, + blink::ServiceWorkerStatusCode status_code) {} + }; + explicit SystemExtensionsInstallManager(Profile* profile); SystemExtensionsInstallManager(const SystemExtensionsInstallManager&) = delete; @@ -36,6 +45,12 @@ return on_command_line_install_finished_; } + void AddObserver(Observer* observer) { observers_.AddObserver(observer); } + + void RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); + } + // TODO(ortuno): Move these to a Registrar or Database. std::vector<SystemExtensionId> GetSystemExtensionIds(); const SystemExtension* GetSystemExtensionById(const SystemExtensionId& id); @@ -66,6 +81,9 @@ void OnAssetsCopiedToProfileDir(OnceInstallCallback final_callback, SystemExtension system_extension, bool did_succeed); + void RegisterServiceWorker(const SystemExtensionId& id); + void OnRegisterServiceWorker(const SystemExtensionId& id, + blink::ServiceWorkerStatusCode status_code); Profile* profile_; @@ -76,6 +94,8 @@ // TODO(ortuno): Move this to a Registrar or Database. std::map<SystemExtensionId, SystemExtension> system_extensions_; + base::ObserverList<Observer> observers_; + base::SequenceBound<IOHelper> io_helper_{ base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
diff --git a/chrome/browser/ash/system_extensions/system_extensions_provider.cc b/chrome/browser/ash/system_extensions/system_extensions_provider.cc index 4cf3312a..4f2536d 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_provider.cc +++ b/chrome/browser/ash/system_extensions/system_extensions_provider.cc
@@ -11,7 +11,6 @@ #include "chrome/browser/ash/system_extensions/system_extension.h" #include "chrome/browser/ash/system_extensions/system_extensions_install_manager.h" #include "chrome/browser/ash/system_extensions/system_extensions_provider_factory.h" -#include "chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/url_constants.h" @@ -36,7 +35,6 @@ } SystemExtensionsProvider::SystemExtensionsProvider(Profile* profile) { - SystemExtensionsWebUIConfigMap::RegisterInstance(); install_manager_ = std::make_unique<SystemExtensionsInstallManager>(profile); }
diff --git a/chrome/browser/ash/system_extensions/system_extensions_ui.cc b/chrome/browser/ash/system_extensions/system_extensions_ui.cc deleted file mode 100644 index 42c7182..0000000 --- a/chrome/browser/ash/system_extensions/system_extensions_ui.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2021 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/ash/system_extensions/system_extensions_ui.h" - -#include "base/logging.h" -#include "chrome/browser/ash/system_extensions/system_extensions_data_source.h" -#include "chrome/browser/profiles/profile.h" -#include "content/public/common/url_constants.h" - -SystemExtensionsWebUIConfig::SystemExtensionsWebUIConfig( - const SystemExtension& system_extension) - : WebUIConfig(content::kChromeUIUntrustedScheme, - system_extension.base_url.host()), - system_extension_id_(system_extension.id), - system_extension_base_url_(system_extension.base_url) {} - -SystemExtensionsWebUIConfig::~SystemExtensionsWebUIConfig() = default; - -std::unique_ptr<content::WebUIController> -SystemExtensionsWebUIConfig::CreateWebUIController(content::WebUI* web_ui) { - return std::make_unique<SystemExtensionsWebUIController>( - web_ui, system_extension_id_, system_extension_base_url_); -} - -SystemExtensionsWebUIController::SystemExtensionsWebUIController( - content::WebUI* web_ui, - const SystemExtensionId& system_extension_id, - const GURL& system_extension_base_url) - : ui::UntrustedWebUIController(web_ui) { - auto* profile = Profile::FromWebUI(web_ui); - auto data_source = std::make_unique<SystemExtensionsDataSource>( - profile, system_extension_id, system_extension_base_url); - content::URLDataSource::Add(profile, std::move(data_source)); -}
diff --git a/chrome/browser/ash/system_extensions/system_extensions_ui.h b/chrome/browser/ash/system_extensions/system_extensions_ui.h deleted file mode 100644 index 4cb46e1..0000000 --- a/chrome/browser/ash/system_extensions/system_extensions_ui.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2021 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_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_UI_H_ -#define CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_UI_H_ - -#include "chrome/browser/ash/system_extensions/system_extension.h" -#include "ui/webui/untrusted_web_ui_controller.h" -#include "ui/webui/webui_config.h" - -// Generic config for System Extensions. Each installed System Extension -// register a WebUIConfig to load its resources. -class SystemExtensionsWebUIConfig : public ui::WebUIConfig { - public: - explicit SystemExtensionsWebUIConfig( - const SystemExtension& system_extension_id); - ~SystemExtensionsWebUIConfig() override; - - // ui::WebUIConfig - std::unique_ptr<content::WebUIController> CreateWebUIController( - content::WebUI* web_ui) override; - - private: - const SystemExtensionId system_extension_id_; - const GURL system_extension_base_url_; -}; - -// Generic WebUIController for System Extensions. Each installed System -// Extension has a corresponding WebUIController. -class SystemExtensionsWebUIController : public ui::UntrustedWebUIController { - public: - explicit SystemExtensionsWebUIController( - content::WebUI* web_ui, - const SystemExtensionId& extension_id, - const GURL& system_extension_base_url); - SystemExtensionsWebUIController(const SystemExtensionsWebUIController&) = - delete; - SystemExtensionsWebUIController& operator=(const UntrustedWebUIController&) = - delete; - ~SystemExtensionsWebUIController() override = default; -}; - -#endif // CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_UI_H_
diff --git a/chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.cc b/chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.cc deleted file mode 100644 index 17dbbd1..0000000 --- a/chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.cc +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2021 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/ash/system_extensions/system_extensions_web_ui_config_map.h" - -#include "base/logging.h" -#include "base/no_destructor.h" -#include "chrome/browser/ash/system_extensions/system_extension.h" -#include "chrome/browser/ash/system_extensions/system_extensions_ui.h" -#include "ui/webui/webui_config.h" - -// static -SystemExtensionsWebUIConfigMap& SystemExtensionsWebUIConfigMap::GetInstance() { - static base::NoDestructor<SystemExtensionsWebUIConfigMap> instance; - return *instance.get(); -} - -// static -void SystemExtensionsWebUIConfigMap::RegisterInstance() { - content::WebUIControllerFactory::RegisterFactory( - &SystemExtensionsWebUIConfigMap::GetInstance()); -} - -SystemExtensionsWebUIConfigMap::SystemExtensionsWebUIConfigMap() = default; - -SystemExtensionsWebUIConfigMap::~SystemExtensionsWebUIConfigMap() = default; - -void SystemExtensionsWebUIConfigMap::AddForSystemExtension( - const SystemExtension& system_extension) { - auto config = std::make_unique<SystemExtensionsWebUIConfig>(system_extension); - configs_[system_extension.base_url.host()] = std::move(config); -} - -const ui::UntrustedWebUIControllerFactory::WebUIConfigMap& -SystemExtensionsWebUIConfigMap::GetWebUIConfigMap() { - return configs_; -}
diff --git a/chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.h b/chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.h deleted file mode 100644 index a7ae9c7..0000000 --- a/chrome/browser/ash/system_extensions/system_extensions_web_ui_config_map.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2021 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_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_WEB_UI_CONFIG_MAP_H_ -#define CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_WEB_UI_CONFIG_MAP_H_ - -#include "chrome/browser/ash/system_extensions/system_extension.h" -#include "ui/webui/untrusted_web_ui_controller_factory.h" - -// This class holds all WebUIConfigs for System Extensions and serves as a -// WebUIControllerFactory for requests to System Extension URLs. -class SystemExtensionsWebUIConfigMap - : public ui::UntrustedWebUIControllerFactory { - public: - static SystemExtensionsWebUIConfigMap& GetInstance(); - static void RegisterInstance(); - - SystemExtensionsWebUIConfigMap(); - SystemExtensionsWebUIConfigMap(const SystemExtensionsWebUIConfigMap&) = - delete; - SystemExtensionsWebUIConfigMap& operator=( - const SystemExtensionsWebUIConfigMap&) = delete; - - void AddForSystemExtension(const SystemExtension& system_extension); - - protected: - const WebUIConfigMap& GetWebUIConfigMap() override; - - private: - ~SystemExtensionsWebUIConfigMap() override; - - WebUIConfigMap configs_; -}; - -#endif // CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_WEB_UI_CONFIG_MAP_H_
diff --git a/chrome/browser/ash/system_extensions/system_extensions_webui_config.cc b/chrome/browser/ash/system_extensions/system_extensions_webui_config.cc new file mode 100644 index 0000000..3646622b --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_webui_config.cc
@@ -0,0 +1,66 @@ +// Copyright 2021 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/ash/system_extensions/system_extensions_webui_config.h" + +#include "base/logging.h" +#include "chrome/browser/ash/system_extensions/system_extensions_data_source.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/common/url_constants.h" +#include "ui/webui/untrusted_web_ui_controller.h" + +namespace { + +void CreateAndAddURLDataSource(Profile* profile, + const SystemExtensionId& system_extension_id, + const GURL& system_extension_base_url) { + auto data_source = std::make_unique<SystemExtensionsDataSource>( + profile, system_extension_id, system_extension_base_url); + content::URLDataSource::Add(profile, std::move(data_source)); +} + +// Generic WebUIController for System Extensions. Each installed System +// Extension has a corresponding WebUIController. +class SystemExtensionsWebUIController : public ui::UntrustedWebUIController { + public: + explicit SystemExtensionsWebUIController( + content::WebUI* web_ui, + const SystemExtensionId& system_extension_id, + const GURL& system_extension_base_url) + : ui::UntrustedWebUIController(web_ui) { + auto* profile = Profile::FromWebUI(web_ui); + CreateAndAddURLDataSource(profile, system_extension_id, + system_extension_base_url); + } + + SystemExtensionsWebUIController(const SystemExtensionsWebUIController&) = + delete; + SystemExtensionsWebUIController& operator=(const UntrustedWebUIController&) = + delete; + ~SystemExtensionsWebUIController() override = default; +}; + +} // namespace + +SystemExtensionsWebUIConfig::SystemExtensionsWebUIConfig( + const SystemExtension& system_extension) + : WebUIConfig(content::kChromeUIUntrustedScheme, + system_extension.base_url.host()), + system_extension_id_(system_extension.id), + system_extension_base_url_(system_extension.base_url) {} + +SystemExtensionsWebUIConfig::~SystemExtensionsWebUIConfig() = default; + +std::unique_ptr<content::WebUIController> +SystemExtensionsWebUIConfig::CreateWebUIController(content::WebUI* web_ui) { + return std::make_unique<SystemExtensionsWebUIController>( + web_ui, system_extension_id_, system_extension_base_url_); +} + +void SystemExtensionsWebUIConfig::RegisterURLDataSource( + content::BrowserContext* browser_context) { + auto* profile = Profile::FromBrowserContext(browser_context); + CreateAndAddURLDataSource(profile, system_extension_id_, + system_extension_base_url_); +}
diff --git a/chrome/browser/ash/system_extensions/system_extensions_webui_config.h b/chrome/browser/ash/system_extensions/system_extensions_webui_config.h new file mode 100644 index 0000000..55b9c76 --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_webui_config.h
@@ -0,0 +1,28 @@ +// Copyright 2021 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_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_WEBUI_CONFIG_H_ +#define CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_WEBUI_CONFIG_H_ + +#include "chrome/browser/ash/system_extensions/system_extension.h" +#include "ui/webui/webui_config.h" + +// Generic config for System Extensions. Each installed System Extension +// register a WebUIConfig to load its resources. +class SystemExtensionsWebUIConfig : public ui::WebUIConfig { + public: + explicit SystemExtensionsWebUIConfig(const SystemExtension& system_extension); + ~SystemExtensionsWebUIConfig() override; + + // ui::WebUIConfig + std::unique_ptr<content::WebUIController> CreateWebUIController( + content::WebUI* web_ui) override; + void RegisterURLDataSource(content::BrowserContext* browser_context) override; + + private: + const SystemExtensionId system_extension_id_; + const GURL system_extension_base_url_; +}; + +#endif // CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_WEBUI_CONFIG_H_
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 b9fee41..93f1bbb 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
@@ -3026,8 +3026,8 @@ HistoryServiceFactory::GetForProfileWithoutCreating(profile); // Create a safe_browsing::VerdictCacheManager that will handle deletion of // ContentSettingsType::PASSWORD_PROTECTION entries. - safe_browsing::VerdictCacheManager sb_cache_manager(history_service, map, - profile->GetPrefs()); + safe_browsing::VerdictCacheManager sb_cache_manager( + history_service, map, profile->GetPrefs(), /*sync_observer=*/nullptr); GURL url("https://example.com");
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index f6f71ad1..7bcfca0 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -54,7 +54,7 @@ #include "chrome/browser/extensions/chrome_extension_cookies.h" #include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/favicon/favicon_utils.h" -#include "chrome/browser/first_party_sets/first_party_sets_settings.h" +#include "chrome/browser/first_party_sets/first_party_sets_pref_names.h" #include "chrome/browser/font_family_cache.h" #include "chrome/browser/gpu/chrome_browser_main_extra_parts_gpu.h" #include "chrome/browser/hid/chrome_hid_delegate.h" @@ -275,6 +275,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_ui_url_loader_factory.h" +#include "content/public/browser/webui_config_map.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" @@ -318,7 +319,6 @@ #include "ui/base/page_transition_types.h" #include "ui/base/resource/resource_bundle.h" #include "ui/native_theme/native_theme.h" -#include "ui/webui/webui_config_map.h" #include "url/gurl.h" #include "url/origin.h" #include "url/third_party/mozilla/url_parse.h" @@ -5669,8 +5669,8 @@ if (!ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL( browser_context, *url) && - !ui::WebUIConfigMap::GetInstance().GetConfig(browser_context, - url::Origin::Create(*url))) { + !content::WebUIConfigMap::GetInstance().GetConfig( + browser_context, url::Origin::Create(*url))) { return false; } @@ -6446,7 +6446,20 @@ } bool ChromeContentBrowserClient::IsFirstPartySetsEnabled() { - return FirstPartySetsSettings::Get()->IsFirstPartySetsEnabled(); + if (!base::FeatureList::IsEnabled(features::kFirstPartySets)) { + return false; + } + if (!g_browser_process) { + // If browser process doesn't exist (e.g. in minimal mode on android), + // default to the feature value which is true since we didn't return above. + return true; + } + PrefService* local_state = g_browser_process->local_state(); + if (!local_state || + !local_state->FindPreference(first_party_sets::kFirstPartySetsEnabled)) { + return true; + } + return local_state->GetBoolean(first_party_sets::kFirstPartySetsEnabled); } content::mojom::AlternativeErrorPageOverrideInfoPtr
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc index 7384276d..b9c9fe1 100644 --- a/chrome/browser/chrome_service_worker_browsertest.cc +++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -15,6 +15,7 @@ #include "base/scoped_observation.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" @@ -46,6 +47,10 @@ #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_controller.h" +#include "content/public/browser/webui_config.h" +#include "content/public/browser/webui_config_map.h" +#include "content/public/common/content_features.h" +#include "content/public/common/url_constants.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "net/dns/mock_host_resolver.h" @@ -53,6 +58,7 @@ #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "ppapi/shared_impl/ppapi_switches.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/messaging/string_message_codec.h" #include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom.h" @@ -800,11 +806,11 @@ TestNoFetchHandler(kInstallAndWaitForActivatedPageWithModuleScript); } -// Copied from devtools_browsertest.cc. +// URLDataSource that serves an empty page for all URLs except source/sw.js +// for which it serves valid service worker code. class StaticURLDataSource : public content::URLDataSource { public: - StaticURLDataSource(const std::string& source, const std::string& content) - : source_(source), content_(content) {} + explicit StaticURLDataSource(const std::string& source) : source_(source) {} StaticURLDataSource(const StaticURLDataSource&) = delete; StaticURLDataSource& operator=(const StaticURLDataSource&) = delete; @@ -816,73 +822,161 @@ void StartDataRequest(const GURL& url, const content::WebContents::Getter& wc_getter, GotDataCallback callback) override { - std::string data(content_); + // If it's the service worker url, serve a valid Service Worker. + if (url.ExtractFileName() == "sw.js") { + // Use a working script instead of an empty one, otherwise the worker + // would fail to be registered. + std::string data = R"( + self.oninstall = function(e) { + e.waitUntil(new Promise(r => { /* never resolve */ })); + }; + self.onfetch = function(e) {}; + )"; + std::move(callback).Run(base::RefCountedString::TakeString(&data)); + return; + } + + // Otherwise, serve an empty page. + std::string data; std::move(callback).Run(base::RefCountedString::TakeString(&data)); } std::string GetMimeType(const std::string& path) override { - return "application/javascript"; + if (path == "sw.js") + return "application/javascript"; + return "text/html"; } bool ShouldAddContentSecurityPolicy() override { return false; } private: const std::string source_; - const std::string content_; }; -// Copied from devtools_browsertest.cc. -class MockWebUIProvider - : public TestChromeWebUIControllerFactory::WebUIProvider { +class StaticWebUIController : public content::WebUIController { public: - MockWebUIProvider(const std::string& source, const std::string& content) - : source_(source), content_(content) {} + StaticWebUIController(content::WebUI* web_ui, const std::string& key) + : WebUIController(web_ui) { + content::URLDataSource::Add(Profile::FromWebUI(web_ui), + std::make_unique<StaticURLDataSource>(key)); + } + ~StaticWebUIController() override = default; +}; - MockWebUIProvider(const MockWebUIProvider&) = delete; - MockWebUIProvider& operator=(const MockWebUIProvider&) = delete; +class TestWebUIConfig : public content::WebUIConfig { + public: + explicit TestWebUIConfig(base::StringPiece scheme, base::StringPiece host) + : content::WebUIConfig(scheme, host) { + data_source_key_ = this->host(); + if (this->scheme() == "chrome-untrusted") { + data_source_key_ = this->scheme() + "://" + this->host() + "/"; + } + } - ~MockWebUIProvider() override = default; + ~TestWebUIConfig() override = default; - std::unique_ptr<content::WebUIController> NewWebUI(content::WebUI* web_ui, - const GURL& url) override { + std::unique_ptr<content::WebUIController> CreateWebUIController( + content::WebUI* web_ui) override { + return std::make_unique<StaticWebUIController>(web_ui, data_source_key_); + } + + void RegisterURLDataSource( + content::BrowserContext* browser_context) override { content::URLDataSource::Add( - Profile::FromWebUI(web_ui), - std::make_unique<StaticURLDataSource>(source_, content_)); - return std::make_unique<content::WebUIController>(web_ui); + browser_context, + std::make_unique<StaticURLDataSource>(data_source_key_)); } private: - const std::string source_; - const std::string content_; + std::string data_source_key_; }; +class ChromeWebUIServiceWorkerTest : public ChromeServiceWorkerTest { + protected: + // Creates a WebUI at `base_url` and registers a service worker for + // it. Returns the result of registering the Service Worker. + blink::ServiceWorkerStatusCode CreateWebUIAndRegisterServiceWorker( + const GURL& base_url) { + auto webui_config = + std::make_unique<TestWebUIConfig>(base_url.scheme(), base_url.host()); + if (base_url.SchemeIs(content::kChromeUIScheme)) { + content::WebUIConfigMap::GetInstance().AddWebUIConfig( + std::move(webui_config)); + } else { + content::WebUIConfigMap::GetInstance().AddUntrustedWebUIConfig( + std::move(webui_config)); + } + + // Try to register the service worker. + const GURL service_worker_url = base_url.Resolve("sw.js"); + base::RunLoop run_loop; + absl::optional<blink::ServiceWorkerStatusCode> result; + blink::mojom::ServiceWorkerRegistrationOptions options( + base_url, blink::mojom::ScriptType::kClassic, + blink::mojom::ServiceWorkerUpdateViaCache::kNone); + blink::StorageKey key(url::Origin::Create(service_worker_url)); + GetServiceWorkerContext()->RegisterServiceWorker( + service_worker_url, key, options, + base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode r) { + result = r; + run_loop.Quit(); + })); + + run_loop.Run(); + return result.value(); + } + + // Creates a WebUI at `base_url` and tries to register a service worker + // for it in JavaScript. Returns "ServiceWorkerRegistered" if it succeeds, + // otherwise it returns the error string. + content::EvalJsResult CreateWebUIAndRegisterServiceWorkerInJavaScript( + const GURL& base_url) { + auto webui_config = + std::make_unique<TestWebUIConfig>(base_url.scheme(), base_url.host()); + if (base_url.SchemeIs(content::kChromeUIScheme)) { + content::WebUIConfigMap::GetInstance().AddWebUIConfig( + std::move(webui_config)); + } else { + content::WebUIConfigMap::GetInstance().AddUntrustedWebUIConfig( + std::move(webui_config)); + } + + CHECK(ui_test_utils::NavigateToURL(browser(), base_url)); + + const GURL service_worker_url = base_url.Resolve("sw.js"); + const std::string register_script = base::StringPrintf( + R"( + (async () => { + const init = {}; + init['scope'] = '%s'; + try { + await navigator.serviceWorker.register('%s', init); + await navigator.serviceWorker.ready; + return "ServiceWorkerRegistered"; + } catch (e) { + return e.message; + } + })() + )", + base_url.spec().c_str(), service_worker_url.spec().c_str()); + return EvalJs(browser()->tab_strip_model()->GetActiveWebContents(), + register_script); + } +}; + +// Tests that registering a service worker in JavaScript with a chrome:// URL +// fails. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerTest, + DisallowChromeSchemeInJavaScript) { + const GURL base_url("chrome://dummyurl"); + auto result = CreateWebUIAndRegisterServiceWorkerInJavaScript(base_url); + EXPECT_EQ( + "Failed to register a ServiceWorker: The URL protocol of the " + "current origin ('chrome://dummyurl') is not supported.", + result); +} + // Tests that registering a service worker with a chrome:// URL fails. -IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest, DisallowChromeScheme) { - const GURL kScript("chrome://dummyurl/sw.js"); - const GURL kScope("chrome://dummyurl"); - - // Make chrome://dummyurl/sw.js serve a service worker script. - TestChromeWebUIControllerFactory test_factory; - MockWebUIProvider mock_provider("serviceworker", "// empty service worker"); - test_factory.AddFactoryOverride(kScript.host(), &mock_provider); - content::WebUIControllerFactory::RegisterFactory(&test_factory); - - // Try to register the service worker. - base::RunLoop run_loop; - blink::ServiceWorkerStatusCode result = blink::ServiceWorkerStatusCode::kOk; - blink::mojom::ServiceWorkerRegistrationOptions options( - kScope, blink::mojom::ScriptType::kClassic, - blink::mojom::ServiceWorkerUpdateViaCache::kImports); - blink::StorageKey key(url::Origin::Create(options.scope)); - GetServiceWorkerContext()->RegisterServiceWorker( - kScript, key, options, - base::BindOnce( - [](base::OnceClosure quit_closure, - blink::ServiceWorkerStatusCode* out_result, - blink::ServiceWorkerStatusCode result) { - *out_result = result; - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure(), &result)); - run_loop.Run(); +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerTest, DisallowChromeScheme) { + const GURL base_url("chrome://dummyurl"); // Registration should fail. This is the desired behavior. At the time of this // writing, there are a few reasons the registration fails: @@ -899,9 +993,92 @@ // It's difficult to change all these, so the test author hasn't actually // changed Chrome in a way that makes this test fail, to prove that the test // would be effective at catching a regression. + auto result = CreateWebUIAndRegisterServiceWorker(base_url); EXPECT_EQ(result, blink::ServiceWorkerStatusCode::kErrorInvalidArguments); } +// Tests that registering a service worker in JavaScript with a +// chrome-untrusted:// URL fails. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerTest, + DisallowChromeUntrustedSchemeInJavaScript) { + const GURL base_url("chrome-untrusted://dummyurl"); + auto result = CreateWebUIAndRegisterServiceWorkerInJavaScript(base_url); + // Even when we add chrome-untrusted:// to the list of Service Worker schemes + // we should fail to register it because the flag is not enabled. + EXPECT_EQ( + "Failed to register a ServiceWorker: The URL protocol of the " + "current origin ('chrome-untrusted://dummyurl') is not supported.", + result); +} + +// Tests that registering a service worker with a chrome-untrusted:// URL fails +// if the flag is not enabled. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerTest, + DisllowChromeUntrustedScheme) { + const GURL base_url("chrome-untrusted://dummyurl"); + + // Similar to the chrome:// test above, but this fails with a kErrorNetwork + // error. This is because chrome-untrusted:// is registered as a Service + // Worker scheme but the loader factories are only added when the + // kEnableServiceWorkersForChromeUntrusted feature is enabled. + auto result = CreateWebUIAndRegisterServiceWorker(base_url); + EXPECT_EQ(result, blink::ServiceWorkerStatusCode::kErrorNetwork); +} + +class ChromeWebUIServiceWorkerUntrustedFlagTest + : public ChromeWebUIServiceWorkerTest { + public: + ChromeWebUIServiceWorkerUntrustedFlagTest() + : features_(features::kEnableServiceWorkersForChromeUntrusted) {} + + private: + base::test::ScopedFeatureList features_; +}; + +// Tests that registering a service worker in JavaScript with a chrome:// URL +// fails even if the untrusted flag is enabled. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerUntrustedFlagTest, + DisallowChromeSchemeInJavaScript) { + const GURL base_url("chrome://dummyurl"); + auto result = CreateWebUIAndRegisterServiceWorkerInJavaScript(base_url); + EXPECT_EQ( + "Failed to register a ServiceWorker: The URL protocol of the " + "current origin ('chrome://dummyurl') is not supported.", + result); +} + +// Tests that registering a service worker with a chrome:// URL fails even +// if the untrusted flag is enabled. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerUntrustedFlagTest, + DisallowChromeScheme) { + const GURL base_url("chrome://dummyurl"); + auto result = CreateWebUIAndRegisterServiceWorker(base_url); + EXPECT_EQ(result, blink::ServiceWorkerStatusCode::kErrorInvalidArguments); +} + +// Tests that registering a service worker with a chrome-untrusted:// URL works +// if the flag is enabled. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerUntrustedFlagTest, + AllowChromeUntrustedScheme) { + const GURL base_url("chrome-untrusted://dummyurl"); + auto result = CreateWebUIAndRegisterServiceWorker(base_url); + EXPECT_EQ(result, blink::ServiceWorkerStatusCode::kOk); +} + +// Tests that registering a service worker in JavaScript with a +// chrome-untrusted:// URL fails. +IN_PROC_BROWSER_TEST_F(ChromeWebUIServiceWorkerUntrustedFlagTest, + AllowChromeUntrustedSchemeInJavaScript) { + const GURL base_url("chrome-untrusted://dummyurl"); + auto result = CreateWebUIAndRegisterServiceWorkerInJavaScript(base_url); + // We expect all WebUI Service Worker registrations to happen from C++ + // so this should fail even when the flag is enabled. + EXPECT_EQ( + "Failed to register a ServiceWorker: The document is in an " + "invalid state.", + result); +} + enum class ServicifiedFeatures { kNone, kServiceWorker, kNetwork }; // A simple fixture used for navigation preload tests so far. The fixture
diff --git a/chrome/browser/chromeos/arc/arc_external_protocol_dialog.cc b/chrome/browser/chromeos/arc/arc_external_protocol_dialog.cc index 4942c9d..343859f 100644 --- a/chrome/browser/chromeos/arc/arc_external_protocol_dialog.cc +++ b/chrome/browser/chromeos/arc/arc_external_protocol_dialog.cc
@@ -130,7 +130,7 @@ if (app_info.empty()) return false; - IntentPickerTabHelper::SetShouldShowIcon( + IntentPickerTabHelper::ShowOrHideIcon( web_contents, bubble_type == apps::IntentPickerBubbleType::kExternalProtocol); browser->window()->ShowIntentPickerBubble( @@ -488,7 +488,8 @@ ClickToCallUiController::GetOrCreateFromWebContents(web_contents.get()) ->OnIntentPickerClosed(); } else { - IntentPickerTabHelper::SetShouldShowIcon(web_contents.get(), false); + IntentPickerTabHelper::ShowOrHideIcon(web_contents.get(), + /*should_show_icon=*/false); } }
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.cc b/chrome/browser/component_updater/first_party_sets_component_installer.cc index 43a9965..8efdef12 100644 --- a/chrome/browser/component_updater/first_party_sets_component_installer.cc +++ b/chrome/browser/component_updater/first_party_sets_component_installer.cc
@@ -18,7 +18,6 @@ #include "base/path_service.h" #include "base/task/thread_pool.h" #include "base/version.h" -#include "chrome/browser/first_party_sets/first_party_sets_settings.h" #include "components/component_updater/component_installer.h" #include "components/component_updater/component_updater_paths.h" #include "content/public/browser/first_party_sets_handler.h" @@ -61,7 +60,7 @@ } base::TaskPriority GetTaskPriority() { - return FirstPartySetsSettings::Get()->IsFirstPartySetsEnabled() + return content::FirstPartySetsHandler::GetInstance()->IsEnabled() ? base::TaskPriority::USER_BLOCKING : base::TaskPriority::BEST_EFFORT; } @@ -73,7 +72,7 @@ // If the component has been installed and can be read, we pass the component // file; otherwise, we pass an invalid file. void SetFirstPartySetsConfig(SetsReadyOnceCallback on_sets_ready) { - if (!FirstPartySetsSettings::Get()->IsFirstPartySetsEnabled() || + if (!content::FirstPartySetsHandler::GetInstance()->IsEnabled() || on_sets_ready.is_null()) { return; }
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc b/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc index 5cc566d..75e0ac3 100644 --- a/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc +++ b/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc
@@ -15,10 +15,10 @@ #include "base/test/test_future.h" #include "base/threading/thread_task_runner_handle.h" #include "base/version.h" -#include "chrome/browser/first_party_sets/first_party_sets_settings.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "components/component_updater/mock_component_updater_service.h" +#include "content/public/browser/first_party_sets_handler.h" #include "content/public/common/content_features.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock.h" @@ -44,7 +44,7 @@ public: FirstPartySetsComponentInstallerTest() { CHECK(component_install_dir_.CreateUniqueTempDir()); - FirstPartySetsSettings::Get()->ResetForTesting(); + content::FirstPartySetsHandler::GetInstance()->ResetForTesting(); } void TearDown() override {
diff --git a/chrome/browser/devtools/protocol/cast_handler.cc b/chrome/browser/devtools/protocol/cast_handler.cc index 1f8c9104..116bf43 100644 --- a/chrome/browser/devtools/protocol/cast_handler.cc +++ b/chrome/browser/devtools/protocol/cast_handler.cc
@@ -182,7 +182,7 @@ return Response::Success(); } -void CastHandler::OnResultsUpdated( +void CastHandler::OnSinksUpdated( const std::vector<media_router::MediaSinkWithCastModes>& sinks) { sinks_ = sinks; SendSinkUpdate();
diff --git a/chrome/browser/devtools/protocol/cast_handler.h b/chrome/browser/devtools/protocol/cast_handler.h index b17ed9f8..bf122eb 100644 --- a/chrome/browser/devtools/protocol/cast_handler.h +++ b/chrome/browser/devtools/protocol/cast_handler.h
@@ -12,6 +12,7 @@ #include "base/containers/flat_set.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/devtools/protocol/cast.h" +#include "chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h" #include "chrome/browser/ui/media_router/query_result_manager.h" #include "components/media_router/browser/issues_observer.h" #include "components/media_router/common/mojom/media_router.mojom.h" @@ -26,7 +27,7 @@ } // namespace media_router class CastHandler : public protocol::Cast::Backend, - public media_router::QueryResultManager::Observer { + public media_router::MediaSinkWithCastModesObserver { public: CastHandler(content::WebContents* web_contents, protocol::UberDispatcher* dispatcher); @@ -49,8 +50,8 @@ protocol::Maybe<std::string> in_presentation_url) override; protocol::Response Disable() override; - // media_router::QueryResultsManager: - void OnResultsUpdated( + // media_router::MediaSinkWithCastModesObserver: + void OnSinksUpdated( const std::vector<media_router::MediaSinkWithCastModes>& sinks) override; private:
diff --git a/chrome/browser/extensions/chrome_extension_cookies.cc b/chrome/browser/extensions/chrome_extension_cookies.cc index 1d550800..0026f11 100644 --- a/chrome/browser/extensions/chrome_extension_cookies.cc +++ b/chrome/browser/extensions/chrome_extension_cookies.cc
@@ -8,7 +8,6 @@ #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/extensions/chrome_extension_cookies_factory.h" -#include "chrome/browser/first_party_sets/first_party_sets_settings.h" #include "chrome/browser/net/profile_network_context_service.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile.h" @@ -17,6 +16,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/cookie_store_factory.h" +#include "content/public/browser/first_party_sets_handler.h" #include "extensions/common/constants.h" #include "net/cookies/cookie_partition_key_collection.h" #include "net/cookies/first_party_set_metadata.h" @@ -28,7 +28,7 @@ ChromeExtensionCookies::ChromeExtensionCookies(Profile* profile) : profile_(profile), first_party_sets_enabled_( - FirstPartySetsSettings::Get()->IsFirstPartySetsEnabled()) { + content::FirstPartySetsHandler::GetInstance()->IsEnabled()) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); cookie_settings_ = CookieSettingsFactory::GetForProfile(profile); cookie_settings_observation_.Observe(cookie_settings_.get());
diff --git a/chrome/browser/extensions/omnibox_focus_interactive_test.cc b/chrome/browser/extensions/omnibox_focus_interactive_test.cc index 1501d7de4..e01edcd4 100644 --- a/chrome/browser/extensions/omnibox_focus_interactive_test.cc +++ b/chrome/browser/extensions/omnibox_focus_interactive_test.cc
@@ -19,6 +19,7 @@ #include "content/public/test/test_navigation_observer.h" #include "extensions/browser/extension_prefs.h" #include "extensions/test/test_extension_dir.h" +#include "third_party/blink/public/common/features.h" namespace extensions { @@ -513,4 +514,59 @@ EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); } +class OmniboxFocusInteractiveFencedFrameTest + : public OmniboxFocusInteractiveTest { + public: + OmniboxFocusInteractiveFencedFrameTest() { + feature_list_.InitAndEnableFeatureWithParameters( + blink::features::kFencedFrames, {{"implementation_type", "mparch"}}); + } + ~OmniboxFocusInteractiveFencedFrameTest() override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(OmniboxFocusInteractiveFencedFrameTest, + NtpReplacementExtension_LoadFencedFrame) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // Open the new tab, focus should be on the location bar. + OpenNewTab(); + + EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); + + // Focus the tab contents. + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + web_contents->Focus(); + EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); + + // FencedFrameTestHelper uses eval() function that is blocked by the + // document's CSP on this page. So need to maually create a fenced frame for + // avoiding the CSP policy. + constexpr char kAddFencedFrameScript[] = R"({ + const fenced_frame = document.createElement('fencedframe'); + fenced_frame.src = $1; + document.body.appendChild(fenced_frame); + })"; + + // Create a fenced frame and load a URL. + // The fenced frame navigation should not affect the view focus. + GURL fenced_frame_url = + embedded_test_server()->GetURL("/fenced_frames/title1.html"); + content::TestNavigationManager navigation(web_contents, fenced_frame_url); + EXPECT_TRUE(content::ExecuteScript( + web_contents->GetMainFrame(), + content::JsReplace(kAddFencedFrameScript, fenced_frame_url))); + navigation.WaitForNavigationFinished(); + + // Verify that after the fenced frame navigation, the tab contents stayed + // focused. + EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); +} + } // namespace extensions
diff --git a/chrome/browser/first_party_sets/BUILD.gn b/chrome/browser/first_party_sets/BUILD.gn index 7e2313d4..733e204 100644 --- a/chrome/browser/first_party_sets/BUILD.gn +++ b/chrome/browser/first_party_sets/BUILD.gn
@@ -17,8 +17,6 @@ "first_party_sets_overrides_policy_handler.h", "first_party_sets_pref_names.cc", "first_party_sets_pref_names.h", - "first_party_sets_settings.cc", - "first_party_sets_settings.h", ] deps = [ "//base",
diff --git a/chrome/browser/first_party_sets/first_party_sets_settings.cc b/chrome/browser/first_party_sets/first_party_sets_settings.cc deleted file mode 100644 index 43deec0..0000000 --- a/chrome/browser/first_party_sets/first_party_sets_settings.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2022 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/first_party_sets/first_party_sets_settings.h" - -#include "chrome/browser/browser_process.h" -#include "chrome/browser/first_party_sets/first_party_sets_pref_names.h" -#include "components/prefs/pref_service.h" -#include "content/public/common/content_features.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace { - -bool IsFirstPartySetsEnabledInternal() { - if (!base::FeatureList::IsEnabled(features::kFirstPartySets)) { - return false; - } - if (!g_browser_process) { - // If browser process doesn't exist (e.g. in minimal mode on android), - // default to the feature value which is true since we didn't return above. - return true; - } - PrefService* local_state = g_browser_process->local_state(); - if (!local_state || - !local_state->FindPreference(first_party_sets::kFirstPartySetsEnabled)) { - return true; - } - return local_state->GetBoolean(first_party_sets::kFirstPartySetsEnabled); -} - -} // namespace - -// static -FirstPartySetsSettings* FirstPartySetsSettings::Get() { - static base::NoDestructor<FirstPartySetsSettings> instance; - return instance.get(); -} - -bool FirstPartySetsSettings::IsFirstPartySetsEnabled() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // This method invokes `IsFirstPartySetsEnabledInternal` and uses the - // `enabled_` variable to memoize the result. We can memoize since the - // First-Party Sets enterprise policy doesn't support `dynamic refresh` and - // the base::Feature doesn't change after start up, the value of this method - // will not change in a single browser session. - if (!enabled_.has_value()) { - enabled_ = absl::make_optional(IsFirstPartySetsEnabledInternal()); - } - return enabled_.value(); -} - -void FirstPartySetsSettings::ResetForTesting() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - enabled_ = absl::nullopt; -}
diff --git a/chrome/browser/first_party_sets/first_party_sets_settings.h b/chrome/browser/first_party_sets/first_party_sets_settings.h deleted file mode 100644 index 145f428..0000000 --- a/chrome/browser/first_party_sets/first_party_sets_settings.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2022 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_FIRST_PARTY_SETS_FIRST_PARTY_SETS_SETTINGS_H_ -#define CHROME_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_SETTINGS_H_ - -#include "base/no_destructor.h" -#include "base/sequence_checker.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -class FirstPartySetsSettings { - public: - static FirstPartySetsSettings* Get(); - - FirstPartySetsSettings() = default; - // Note that FirstPartySetsSettings is a singleton that's never destroyed. - ~FirstPartySetsSettings() = delete; - FirstPartySetsSettings(const FirstPartySetsSettings&) = delete; - FirstPartySetsSettings& operator=(const FirstPartySetsSettings&) = delete; - - bool IsFirstPartySetsEnabled(); - void ResetForTesting(); - - private: - friend class base::NoDestructor<FirstPartySetsSettings>; - - absl::optional<bool> enabled_ GUARDED_BY_CONTEXT(sequence_checker_) = - absl::nullopt; - - SEQUENCE_CHECKER(sequence_checker_); -}; - -#endif // CHROME_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_SETTINGS_H_ \ No newline at end of file
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index e71a637..f9e4664 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2730,7 +2730,7 @@ { "name": "enable-tab-grid-layout", "owners": [ "memex-team@google.com" ], - "expiry_milestone": 101 + "expiry_milestone": 105 }, { "name": "enable-tab-groups", @@ -2740,7 +2740,7 @@ { "name": "enable-tab-groups-continuation", "owners": [ "memex-team@google.com" ], - "expiry_milestone": 101 + "expiry_milestone": 105 }, { "name": "enable-tab-groups-for-tablets", @@ -5009,16 +5009,6 @@ "expiry_milestone": -1 }, { - "name": "reading-list-messages", - "owners": [ "thegreenfrog@google.com", "bling-flags@google.com" ], - "expiry_milestone": 99 - }, - { - "name": "reading-list-time-to-read", - "owners": [ "thegreenfrog@google.com", "bling-flags@google.com" ], - "expiry_milestone": 100 - }, - { "name": "record-snapshot-size", "owners": ["edchin","bling-flags@google.com"], "expiry_milestone": 91
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java index 2362c87..7ab6950 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java
@@ -203,7 +203,7 @@ TestThreadUtils.runOnUiThreadBlocking(moreButton::dismiss); // Toggle the switch. - onView(withId(R.id.switchWidget)).perform(click()); + TestThreadUtils.runOnUiThreadBlocking((Runnable) pref::performClick); TestThreadUtils.runOnUiThreadBlocking(() -> { Assert.assertEquals("Preference of 'offer to translate' should be toggled when switch " + "widget is clicked.",
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.cc index a2b1912..ffe85ec 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.cc
@@ -111,9 +111,111 @@ device_time_pref->SetKey(sink_id, base::TimeToValue(base::Time::Now())); } +const base::Value* AccessCodeCastPrefUpdater::GetDevicesDict() { + return pref_service_->GetDictionary(prefs::kAccessCodeCastDevices); +} + +const base::Value* AccessCodeCastPrefUpdater::GetDiscoveredNetworksDict() { + return pref_service_->GetDictionary(prefs::kAccessCodeCastDiscoveredNetworks); +} + +const base::Value* AccessCodeCastPrefUpdater::GetDeviceAdditionTimeDict() { + return pref_service_->GetDictionary(prefs::kAccessCodeCastDeviceAdditionTime); +} + +const base::Value::List* AccessCodeCastPrefUpdater::GetSinkIdsByNetworkId( + const std::string& network_id) { + auto* network_dict = GetDiscoveredNetworksDict(); + if (!network_dict) + return nullptr; + + // If found, it returns a pointer to the element. Otherwise it returns + // nullptr. + auto* network_list = network_dict->FindKey(network_id); + + if (!network_list) + return nullptr; + return network_list->GetIfList(); +} + +const base::Value* AccessCodeCastPrefUpdater::GetMediaSinkInternalValueBySinkId( + const MediaSink::Id sink_id) { + auto* device_dict = GetDevicesDict(); + if (!device_dict) + return nullptr; + + // If found, it returns a pointer to the element. Otherwise it returns + // nullptr. + auto* device_value = device_dict->FindKey(sink_id); + + if (!device_value) + return nullptr; + return device_value; +} + +void AccessCodeCastPrefUpdater::RemoveSinkIdFromDevicesDict( + const MediaSink::Id sink_id) { + ScopedDictionaryPrefUpdate update(pref_service_, + prefs::kAccessCodeCastDevices); + std::unique_ptr<DictionaryValueUpdate> devices_pref = update.Get(); + DCHECK(devices_pref) << "The " << prefs::kAccessCodeCastDevices + << " pref does not exist."; + devices_pref->Remove(sink_id); +} + +void AccessCodeCastPrefUpdater::RemoveSinkIdFromDiscoveredNetworksDict( + const MediaSink::Id sink_id) { + ScopedDictionaryPrefUpdate update(pref_service_, + prefs::kAccessCodeCastDiscoveredNetworks); + std::unique_ptr<DictionaryValueUpdate> discovered_networks_pref = + update.Get(); + DCHECK(discovered_networks_pref) + << "The " << prefs::kAccessCodeCastDiscoveredNetworks + << " pref does not exist."; + + const base::Value::Dict& network_dict = + GetDiscoveredNetworksDict()->GetDict(); + + // Iterate through network id's + for (auto key_value_pair : network_dict) { + const auto network_id = key_value_pair.first; + + // We need to clone here because the GetList() method returns a const value + // and we might need to modify it later on. + base::Value::List network_list = key_value_pair.second.GetList().Clone(); + + // Check to see if the media sink was erased from the list. If there is no + // value in the list simply continue in the iteration. + if (!network_list.EraseValue(base::Value(sink_id))) + continue; + + // If the list is now empty, remove the key from the dictionary + // entirely and continue from this iteration. + + if (network_list.empty()) { + DCHECK(discovered_networks_pref->Remove(network_id)) + << "The network_id list value exists but the key does not."; + continue; + } + discovered_networks_pref->Set( + network_id, + base::Value::ToUniquePtrValue(base::Value(std::move(network_list)))); + } +} + +void AccessCodeCastPrefUpdater::RemoveSinkIdFromDeviceAdditionTimeDict( + const MediaSink::Id sink_id) { + ScopedDictionaryPrefUpdate update(pref_service_, + prefs::kAccessCodeCastDeviceAdditionTime); + + std::unique_ptr<DictionaryValueUpdate> device_time_pref = update.Get(); + DCHECK(device_time_pref) << "The " << prefs::kAccessCodeCastDeviceAdditionTime + << " pref does not exist."; + device_time_pref->Remove(sink_id); +} + base::WeakPtr<AccessCodeCastPrefUpdater> AccessCodeCastPrefUpdater::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } - } // namespace media_router
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.h b/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.h index ee379cec..0990101 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.h +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater.h
@@ -41,6 +41,42 @@ // exist, then update the value of that |sink_id| with a new time. void UpdateDeviceAdditionTimeDict(const MediaSink::Id sink_id); + // Returns a nullptr if the device dictionary does not exist in the pref + // service for some reason. + const base::Value* GetDevicesDict(); + + // Returns a nullptr if the network dictionary does not exist in the pref + // service for some reason. + const base::Value* GetDiscoveredNetworksDict(); + + // Returns a nullptr if the device addition dictionary does not exist in the + // pref service for some reason. + const base::Value* GetDeviceAdditionTimeDict(); + + // If found, it returns a pointer to the element. Otherwise it returns + // nullptr. + const base::Value::List* GetSinkIdsByNetworkId(const std::string& network_id); + + // If found, it returns a pointer to the element. Otherwise it returns + // nullptr. + const base::Value* GetMediaSinkInternalValueBySinkId( + const MediaSink::Id sink_id); + + // Removes the given |sink_id| from all instances in the devices dictionary + // stored in the pref service. Nothing occurs if the |sink_id| was not there + // in the first place. + void RemoveSinkIdFromDevicesDict(const MediaSink::Id sink_id); + + // Removes the given |sink_id| from all instances in the network dictionary + // stored in the pref service. Nothing occurs if the |sink_id| was not there + // in the first place. + void RemoveSinkIdFromDiscoveredNetworksDict(const MediaSink::Id sink_id); + + // Removes the given |sink_id| from all instances in the device addition + // dictionary stored in the pref service. Nothing occurs if the |sink_id| was + // not there in the first place. + void RemoveSinkIdFromDeviceAdditionTimeDict(const MediaSink::Id sink_id); + base::WeakPtr<AccessCodeCastPrefUpdater> GetWeakPtr(); private:
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater_unittest.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater_unittest.cc index efd9356..bbc1bea 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater_unittest.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_pref_updater_unittest.cc
@@ -195,4 +195,137 @@ EXPECT_GE(final_time_of_addition, initial_time_of_addition); } +TEST_F(AccessCodeCastPrefUpdaterTest, TestGetSinkIdsByNetworkId) { + MediaSinkInternal cast_sink = CreateCastSink(1); + + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink.id(), network1); + + EXPECT_TRUE(pref_updater()->GetSinkIdsByNetworkId(network1)); + EXPECT_FALSE(pref_updater()->GetSinkIdsByNetworkId(network2)); +} + +TEST_F(AccessCodeCastPrefUpdaterTest, TestGetMediaSinkInternalValueBySinkId) { + MediaSinkInternal cast_sink = CreateCastSink(1); + MediaSinkInternal cast_sink2 = CreateCastSink(2); + + pref_updater()->UpdateDevicesDict(cast_sink); + + EXPECT_TRUE( + pref_updater()->GetMediaSinkInternalValueBySinkId(cast_sink.id())); + EXPECT_FALSE( + pref_updater()->GetMediaSinkInternalValueBySinkId(cast_sink2.id())); +} + +TEST_F(AccessCodeCastPrefUpdaterTest, TestRemoveSinkIdFromDevicesDict) { + MediaSinkInternal cast_sink = CreateCastSink(1); + MediaSinkInternal cast_sink2 = CreateCastSink(2); + + pref_updater()->UpdateDevicesDict(cast_sink); + + pref_updater()->RemoveSinkIdFromDevicesDict(cast_sink.id()); + auto* dict = prefs()->GetDictionary(prefs::kAccessCodeCastDevices); + EXPECT_FALSE(dict->FindKey(cast_sink.id())); + pref_updater()->RemoveSinkIdFromDevicesDict(cast_sink2.id()); +} + +TEST_F(AccessCodeCastPrefUpdaterTest, + TestRemoveSinkIdFromDiscoveredNetworksDict) { + MediaSinkInternal cast_sink = CreateCastSink(1); + MediaSinkInternal cast_sink2 = CreateCastSink(2); + + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink.id(), network1); + + pref_updater()->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink.id()); + auto& dict = prefs() + ->GetDictionary(prefs::kAccessCodeCastDiscoveredNetworks) + ->GetDict(); + EXPECT_FALSE(dict.FindList(network1)); +} + +TEST_F(AccessCodeCastPrefUpdaterTest, + TestRemoveSinkIdFromDiscoveredNetworksDictMultipleSinks) { + MediaSinkInternal cast_sink = CreateCastSink(1); + MediaSinkInternal cast_sink2 = CreateCastSink(2); + + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink.id(), network1); + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink2.id(), network1); + + // After removal of a single sink_id, the network key should still exist but + // the list no longer should contain the removed cast sink id. + + pref_updater()->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink.id()); + auto& dict = prefs() + ->GetDictionary(prefs::kAccessCodeCastDiscoveredNetworks) + ->GetDict(); + auto network_list_value = dict.FindList(network1)->Clone(); + + // This method returns the amount of values erased from the list. The second + // cast sink should still be in this network list so it should return 1. + EXPECT_FALSE(network_list_value.EraseValue(base::Value(cast_sink.id()))); + EXPECT_EQ(1u, network_list_value.EraseValue(base::Value(cast_sink2.id()))); + + // Remove the final sink. + + pref_updater()->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink2.id()); + auto& updated_dict = + prefs() + ->GetDictionary(prefs::kAccessCodeCastDiscoveredNetworks) + ->GetDict(); + EXPECT_FALSE(updated_dict.FindList(network1)); +} + +TEST_F(AccessCodeCastPrefUpdaterTest, + TestRemoveSinkIdFromDiscoveredNetworksDictMultipleNetworks) { + MediaSinkInternal cast_sink = CreateCastSink(1); + MediaSinkInternal cast_sink2 = CreateCastSink(2); + MediaSinkInternal cast_sink3 = CreateCastSink(3); + + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink.id(), network1); + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink2.id(), network1); + pref_updater()->UpdateDiscoveredNetworksDict(cast_sink3.id(), network2); + + // After removal of a single sink_id, the network key should still exist but + // the list no longer should contain the removed cast sink id. + + pref_updater()->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink.id()); + auto& dict = prefs() + ->GetDictionary(prefs::kAccessCodeCastDiscoveredNetworks) + ->GetDict(); + auto network1_list_value = dict.FindList(network1)->Clone(); + auto network2_list_value = dict.FindList(network2)->Clone(); + + // This method returns the amount of values erased from the list. The second + // cast sink should still be in this network list so it should return 1. + EXPECT_FALSE(network1_list_value.EraseValue(base::Value(cast_sink.id()))); + EXPECT_EQ(1u, network1_list_value.EraseValue(base::Value(cast_sink2.id()))); + EXPECT_EQ(1u, network2_list_value.EraseValue(base::Value(cast_sink3.id()))); + + // Remove the final two sinks. + + pref_updater()->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink2.id()); + + pref_updater()->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink3.id()); + auto& updated_dict = + prefs() + ->GetDictionary(prefs::kAccessCodeCastDiscoveredNetworks) + ->GetDict(); + + EXPECT_FALSE(updated_dict.FindList(network1)); + EXPECT_FALSE(updated_dict.FindList(network2)); +} + +TEST_F(AccessCodeCastPrefUpdaterTest, + TestRemoveSinkIdFromDeviceAdditionTimeDict) { + MediaSinkInternal cast_sink = CreateCastSink(1); + MediaSinkInternal cast_sink2 = CreateCastSink(2); + + pref_updater()->UpdateDeviceAdditionTimeDict(cast_sink.id()); + + pref_updater()->RemoveSinkIdFromDeviceAdditionTimeDict(cast_sink.id()); + auto* dict = prefs()->GetDictionary(prefs::kAccessCodeCastDeviceAdditionTime); + EXPECT_FALSE(dict->FindKey(cast_sink.id())); + + pref_updater()->RemoveSinkIdFromDeviceAdditionTimeDict(cast_sink2.id()); +} + } // namespace media_router
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc index e8baaa5..b8c02f0 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc
@@ -61,17 +61,20 @@ AccessCodeCastSinkService::AccessCodeCastSinkService( Profile* profile, MediaRouter* media_router, - CastMediaSinkServiceImpl* cast_media_sink_service_impl) + CastMediaSinkServiceImpl* cast_media_sink_service_impl, + DiscoveryNetworkMonitor* network_monitor, + PrefService* prefs) : profile_(profile), media_router_(media_router), media_routes_observer_( std::make_unique<AccessCodeMediaRoutesObserver>(media_router, this)), cast_media_sink_service_impl_(cast_media_sink_service_impl), task_runner_(base::SequencedTaskRunnerHandle::Get()), - network_monitor_(DiscoveryNetworkMonitor::GetInstance()) { - DCHECK(profile_); - pref_updater_ = - std::make_unique<AccessCodeCastPrefUpdater>(profile_->GetPrefs()); + network_monitor_(network_monitor) { + DCHECK(profile_) << "The profile does not exist."; + DCHECK(prefs) + << "Prefs could not be fetched from the profile for some reason."; + pref_updater_ = std::make_unique<AccessCodeCastPrefUpdater>(prefs); backoff_policy_ = { // Number of initial errors (in sequence) to ignore before going into // exponential backoff. @@ -100,6 +103,11 @@ // successful requests. false, }; + // We don't need to post this task per the DiscoveryNetworkMonitor's promise: + // "All observers will be notified of network changes on the thread from which + // they registered." + network_monitor_->AddObserver(this); + InitStoredDeviceConnections(); } AccessCodeCastSinkService::AccessCodeCastSinkService(Profile* profile) @@ -107,7 +115,9 @@ profile, MediaRouterFactory::GetApiForBrowserContext(profile), media_router::DualMediaSinkService::GetInstance() - ->GetCastMediaSinkServiceImpl()) {} + ->GetCastMediaSinkServiceImpl(), + DiscoveryNetworkMonitor::GetInstance(), + profile->GetPrefs()) {} AccessCodeCastSinkService::~AccessCodeCastSinkService() = default; @@ -136,7 +146,7 @@ // There should only be 1 element in the |removed_routes| set. DCHECK(removed_routes.size() < 2); auto first = removed_routes.begin(); - MediaRoute::Id removed_route_id = *first; + removed_route_id_ = *first; base::PostTaskAndReplyWithResult( access_code_sink_service_->cast_media_sink_service_impl_->task_runner() @@ -146,7 +156,7 @@ &CastMediaSinkServiceImpl::GetSinkById, base::Unretained( access_code_sink_service_->cast_media_sink_service_impl_), - MediaRoute::GetSinkIdFromMediaRouteId(removed_route_id)), + MediaRoute::GetSinkIdFromMediaRouteId(removed_route_id_)), base::BindOnce( &AccessCodeCastSinkService::HandleMediaRouteDiscoveredByAccessCode, access_code_sink_service_->GetWeakPtr())); @@ -404,6 +414,143 @@ pref_updater_->UpdateDeviceAdditionTimeDict(sink->id()); } +void AccessCodeCastSinkService::InitStoredDeviceConnections() { + // The AddStoredDevicesToMediaRouter() callback needs to be be + // bound with BindPostTask() to ensure that the callback is invoked on this + // specific task runner. + auto network_cb = + base::BindOnce(&AccessCodeCastSinkService::FetchAndAddStoredDevices, + weak_ptr_factory_.GetWeakPtr()); + + auto returned_network_cb = + base::BindPostTask(task_runner_, std::move(network_cb)); + + // We need to run this task on the IO thread since the DiscoveryNetworkMonitor + // runs on the IO thread. + cast_media_sink_service_impl_->task_runner()->PostTask( + FROM_HERE, base::BindOnce(&DiscoveryNetworkMonitor::Refresh, + base::Unretained(network_monitor_), + std::move(returned_network_cb))); +} + +void AccessCodeCastSinkService::FetchAndAddStoredDevices( + const std::string& network_id) { + // If the network id exists within the pref service, attempt to open any + // devices in that list. + auto* network_list = pref_updater_->GetSinkIdsByNetworkId(network_id); + if (!network_list) { + media_router_->GetLogger()->LogInfo( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "There are no saved Access Code Cast devices on the network_id: " + + network_id, + "", "", ""); + return; + } + media_router_->GetLogger()->LogInfo( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "Found Access Code Cast devices on the network_id: " + network_id + + " : " + network_list->DebugString() + + ". Attempting to add these cast devices to the media router.", + "", "", ""); + AddStoredDevicesToMediaRouter(*network_list); +} + +void AccessCodeCastSinkService::AddStoredDevicesToMediaRouter( + const base::Value::List& sink_ids) { + // We can assume the network_list variable will never be empty since after + // removal of a device, a check is made to ensure that keys with empty lists + // are removed. + std::vector<MediaSinkInternal> cast_sinks; + for (const auto& sink_id : sink_ids) { + const std::string* sink_id_string = sink_id.GetIfString(); + if (!sink_id_string) { + media_router_->GetLogger()->LogError( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "The Media Sink id is not stored as a string in the network list: " + + sink_ids.DebugString() + + ". This means something went wrong when storing cast devices on " + "this network.", + "", "", ""); + return; + } + auto validation_result = ValidateDeviceFromSinkId(*sink_id_string); + + // Ensure that stored media sink_id corresponds to a properly stored + // MediaSinkInternal before adding the given sink_id to the media router. + if (!validation_result.has_value()) { + media_router_->GetLogger()->LogError( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "The Media Sink id " + *sink_id_string + + " is missing from one or more of the pref " + "services. Attempting to remove all sink_id references right " + "now.", + "", "", ""); + RemoveSinkIdFromAllEntries(*sink_id_string); + return; + } + cast_sinks.push_back(validation_result.value()); + } + + // Let the media router handle addition. + cast_media_sink_service_impl_->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&CastMediaSinkServiceImpl::OpenChannelsWithRandomizedDelay, + base::Unretained(cast_media_sink_service_impl_), + cast_sinks, SinkSource::kAccessCode)); +} + +void AccessCodeCastSinkService::RemoveSinkIdFromAllEntries( + const MediaSink::Id& sink_id) { + pref_updater_->RemoveSinkIdFromDevicesDict(sink_id); + pref_updater_->RemoveSinkIdFromDiscoveredNetworksDict(sink_id); + pref_updater_->RemoveSinkIdFromDeviceAdditionTimeDict(sink_id); +} + +const absl::optional<MediaSinkInternal> +AccessCodeCastSinkService::ValidateDeviceFromSinkId( + const MediaSink::Id& sink_id) { + const auto* sink_value = + pref_updater_->GetMediaSinkInternalValueBySinkId(sink_id); + if (!sink_value) { + media_router_->GetLogger()->LogError( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "The Media Sink id: " + sink_id + + " is either stored improperly or doesn't exist within the pref " + "service.", + "", "", ""); + return absl::nullopt; + } + const auto* dict_value = sink_value->GetIfDict(); + if (!dict_value) { + media_router_->GetLogger()->LogError( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "The Media Sink id: " + sink_id + + " was not stored as a dictionary value in the pref service. Its " + "storage type is: " + + base::Value::GetTypeName(sink_value->type()), + "", "", ""); + return absl::nullopt; + } + const absl::optional<MediaSinkInternal> media_sink = + ParseValueDictIntoMediaSinkInternal(*dict_value); + if (!media_sink.has_value()) { + media_router_->GetLogger()->LogError( + mojom::LogCategory::kDiscovery, kLoggerComponent, + "The Media Sink " + dict_value->DebugString() + + " could not be parsed from the pref service.", + "", "", ""); + return absl::nullopt; + } + // TODO(gbj): Include a validation check for the + // prefs::kAccessCodeCastDeviceAdditionTime pref once it is used. + return media_sink.value(); +} + +void AccessCodeCastSinkService::OnNetworksChanged( + const std::string& network_id) { + FetchAndAddStoredDevices(network_id); +} + void AccessCodeCastSinkService::Shutdown() { // There's no guarantee that MediaRouter is still in the // MediaRoutesObserver. |media_routes_observer_| accesses MediaRouter in its
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h index 26b3f781..a28e33d 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h
@@ -27,7 +27,8 @@ using ChannelOpenedCallback = base::OnceCallback<void(bool)>; using AddSinkResultCode = access_code_cast::mojom::AddSinkResultCode; -class AccessCodeCastSinkService : public KeyedService { +class AccessCodeCastSinkService : public KeyedService, + public DiscoveryNetworkMonitor::Observer { public: using DiscoveryDevice = chrome_browser_media::proto::DiscoveryDevice; @@ -86,6 +87,8 @@ // Set of route ids that is updated whenever OnRoutesUpdated is called. std::vector<MediaRoute::Id> old_routes_; + MediaRoute::Id removed_route_id_; + const raw_ptr<AccessCodeCastSinkService> access_code_sink_service_; base::WeakPtrFactory<AccessCodeMediaRoutesObserver> weak_ptr_factory_{this}; @@ -115,12 +118,21 @@ OnChannelOpenedFailure); FRIEND_TEST_ALL_PREFIXES(AccessCodeCastSinkServiceTest, SinkDoesntExistForPrefs); + FRIEND_TEST_ALL_PREFIXES(AccessCodeCastSinkServiceTest, + TestFetchAndAddStoredDevices); + FRIEND_TEST_ALL_PREFIXES(AccessCodeCastSinkServiceTest, TestChangeNetworks); + FRIEND_TEST_ALL_PREFIXES(AccessCodeCastSinkServiceTest, + TestAddInvalidDevicesNoMediaSinkInternal); + FRIEND_TEST_ALL_PREFIXES(AccessCodeCastSinkServiceTest, + TestFetchAndAddStoredDevicesNoNetwork); // Constructor used for testing. AccessCodeCastSinkService( Profile* profile, MediaRouter* media_router, - CastMediaSinkServiceImpl* cast_media_sink_service_impl); + CastMediaSinkServiceImpl* cast_media_sink_service_impl, + DiscoveryNetworkMonitor* network_monitor, + PrefService* prefs); // Use |AccessCodeCastSinkServiceFactory::GetForProfile(..)| to get // an instance of this service. @@ -140,6 +152,23 @@ AddSinkResultCallback add_sink_callback, bool has_sink); + void InitStoredDeviceConnections(); + void FetchAndAddStoredDevices(const std::string& network_id); + void AddStoredDevicesToMediaRouter(const base::Value::List& sink_ids); + + // Removes the given |sink_id| from all entries in the AccessCodeCast pref + // service. + void RemoveSinkIdFromAllEntries(const MediaSink::Id& sink_id); + + // Validates the given |sink_id| is present and properly stored as a + // MediaSinkInternal in the pref store. If the sink is present, a + // MediaSinkInternal will be returned in the optional value. + const absl::optional<MediaSinkInternal> ValidateDeviceFromSinkId( + const MediaSink::Id& sink_id); + + // DiscoveryNetworkMonitor::Observer implementation + void OnNetworksChanged(const std::string& network_id) override; + cast_channel::CastSocketOpenParams CreateCastSocketOpenParams( const MediaSinkInternal& sink);
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_factory.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_factory.cc index e4017cd1c..31c84fd 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_factory.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_factory.cc
@@ -22,7 +22,7 @@ // GetServiceForBrowserContext returns a KeyedService hence the static_cast<> // to return a pointer to AccessCodeCastSinkService. return static_cast<AccessCodeCastSinkService*>( - GetInstance()->GetServiceForBrowserContext(profile, true)); + GetInstance()->GetServiceForBrowserContext(profile, false)); } // static @@ -42,12 +42,16 @@ KeyedService* AccessCodeCastSinkServiceFactory::BuildServiceInstanceFor( content::BrowserContext* profile) const { + if (!GetAccessCodeCastEnabledPref( + Profile::FromBrowserContext(profile)->GetPrefs())) { + return nullptr; + } return new AccessCodeCastSinkService(static_cast<Profile*>(profile)); } bool AccessCodeCastSinkServiceFactory::ServiceIsCreatedWithBrowserContext() const { - return false; + return true; } bool AccessCodeCastSinkServiceFactory::ServiceIsNULLWhileTesting() const {
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc index bccf164f..2e6d579 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/test_mock_time_task_runner.h" #include "base/timer/mock_timer.h" #include "chrome/browser/media/router/chrome_media_router_factory.h" +#include "chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h" #include "chrome/browser/media/router/discovery/access_code/access_code_test_util.h" #include "chrome/browser/media/router/discovery/discovery_network_monitor.h" #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h" @@ -35,6 +36,7 @@ #include "components/media_router/browser/test/mock_media_router.h" #include "components/media_router/common/discovery/media_sink_service_base.h" #include "components/media_router/common/test/test_helper.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/test_utils.h" @@ -75,9 +77,10 @@ std::make_unique<MockCastMediaSinkServiceImpl>( OnSinksDiscoveredCallback(), mock_cast_socket_service_.get(), - DiscoveryNetworkMonitor::GetInstance(), + discovery_network_monitor_.get(), &dual_media_sink_service_)) { mock_cast_socket_service_->SetTaskRunnerForTest(mock_time_task_runner_); + RegisterAccessCodeProfilePrefs(prefs_.registry()); } AccessCodeCastSinkServiceTest(AccessCodeCastSinkServiceTest&) = delete; AccessCodeCastSinkServiceTest& operator=(AccessCodeCastSinkServiceTest&) = @@ -95,9 +98,11 @@ access_code_cast_sink_service_ = base::WrapUnique(new AccessCodeCastSinkService( - profile_, router_.get(), cast_media_sink_service_impl_.get())); + profile_, router_.get(), cast_media_sink_service_impl_.get(), + discovery_network_monitor_.get(), prefs())); access_code_cast_sink_service_->SetTaskRunnerForTest( mock_time_task_runner_); + task_environment_.RunUntilIdle(); } void TearDown() override { @@ -118,12 +123,33 @@ } TestingProfileManager* profile_manager() { return profile_manager_.get(); } + sync_preferences::TestingPrefServiceSyncable* prefs() { return &prefs_; } + + void ChangeConnectionType(network::mojom::ConnectionType connection_type) { + discovery_network_monitor_->OnConnectionChanged(connection_type); + } + protected: content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfileManager> profile_manager_; std::unique_ptr<media_router::MockMediaRouter> router_; std::unique_ptr<LoggerImpl> logger_; + sync_preferences::TestingPrefServiceSyncable prefs_; + + static std::vector<DiscoveryNetworkInfo> fake_network_info_; + + static const std::vector<DiscoveryNetworkInfo> fake_ethernet_info_; + static const std::vector<DiscoveryNetworkInfo> fake_wifi_info_; + static const std::vector<DiscoveryNetworkInfo> fake_unknown_info_; + + static std::vector<DiscoveryNetworkInfo> FakeGetNetworkInfo() { + return fake_network_info_; + } + + std::unique_ptr<DiscoveryNetworkMonitor> discovery_network_monitor_ = + DiscoveryNetworkMonitor::CreateInstanceForTest(&FakeGetNetworkInfo); + raw_ptr<TestingProfile> profile_; scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner_; @@ -138,6 +164,25 @@ std::unique_ptr<AccessCodeCastSinkService> access_code_cast_sink_service_; }; +// static +const std::vector<DiscoveryNetworkInfo> + AccessCodeCastSinkServiceTest::fake_ethernet_info_ = { + DiscoveryNetworkInfo{std::string("enp0s2"), std::string("ethernet1")}}; +// static +const std::vector<DiscoveryNetworkInfo> + AccessCodeCastSinkServiceTest::fake_wifi_info_ = { + DiscoveryNetworkInfo{std::string("wlp3s0"), std::string("wifi1")}, + DiscoveryNetworkInfo{std::string("wlp3s1"), std::string("wifi2")}}; +// static +const std::vector<DiscoveryNetworkInfo> + AccessCodeCastSinkServiceTest::fake_unknown_info_ = { + DiscoveryNetworkInfo{std::string("enp0s2"), std::string()}}; + +// static +std::vector<DiscoveryNetworkInfo> + AccessCodeCastSinkServiceTest::fake_network_info_ = + AccessCodeCastSinkServiceTest::fake_ethernet_info_; + TEST_F(AccessCodeCastSinkServiceTest, AccessCodeCastDeviceRemovedAfterRouteEnds) { // Test to see that an AccessCode cast sink will be removed after the session @@ -149,10 +194,12 @@ MediaRoute media_route_cast = CreateRouteForTesting(cast_sink1); std::vector<MediaRoute> route_list = {media_route_cast}; - // Expect that no Task is posted since no routes were removed. + // Expect that the removed_route_id_ member variable has not changes since no + // route was removed. access_code_cast_sink_service_->media_routes_observer_->OnRoutesUpdated( route_list); - EXPECT_EQ(0u, mock_time_task_runner()->GetPendingTaskCount()); + EXPECT_TRUE(access_code_cast_sink_service_->media_routes_observer_ + ->removed_route_id_.empty()); // Add a cast sink discovered by access code to the list of routes. MediaSinkInternal access_code_sink2 = CreateCastSink(2); @@ -161,10 +208,12 @@ route_list.push_back(media_route_access); - // Expect that no Task is posted since no routes were removed. + // Expect that the removed_route_id_ member variable has not changes since no + // route was removed. access_code_cast_sink_service_->media_routes_observer_->OnRoutesUpdated( route_list); - EXPECT_EQ(0u, mock_time_task_runner()->GetPendingTaskCount()); + EXPECT_TRUE(access_code_cast_sink_service_->media_routes_observer_ + ->removed_route_id_.empty()); // Remove the non-access code sink from the list of routes. route_list.erase( @@ -172,7 +221,9 @@ route_list.end()); access_code_cast_sink_service_->media_routes_observer_->OnRoutesUpdated( route_list); - EXPECT_EQ(1u, mock_time_task_runner()->GetPendingTaskCount()); + EXPECT_EQ( + access_code_cast_sink_service_->media_routes_observer_->removed_route_id_, + media_route_cast.media_route_id()); mock_time_task_runner()->FastForwardUntilNoTasksRemain(); // Expect cast sink is NOT removed from the media router since it @@ -190,7 +241,9 @@ access_code_cast_sink_service_->media_routes_observer_->OnRoutesUpdated( route_list); - EXPECT_EQ(1u, mock_time_task_runner()->GetPendingTaskCount()); + EXPECT_EQ( + access_code_cast_sink_service_->media_routes_observer_->removed_route_id_, + media_route_access.media_route_id()); mock_time_task_runner()->FastForwardUntilNoTasksRemain(); access_code_cast_sink_service_->HandleMediaRouteDiscoveredByAccessCode( @@ -247,7 +300,9 @@ access_code_cast_sink_service_->media_routes_observer_->OnRoutesUpdated({}); // Since a route has been removed, there should be a pending task to examine // whether the route's sink is an access code sink. - EXPECT_EQ(1u, mock_time_task_runner()->GetPendingTaskCount()); + EXPECT_EQ( + access_code_cast_sink_service_->media_routes_observer_->removed_route_id_, + media_route_cast.media_route_id()); access_code_cast_sink_service_->HandleMediaRouteDiscoveredByAccessCode( &cast_sink1); @@ -359,4 +414,272 @@ EXPECT_FALSE(mock_time_task_runner()->GetPendingTaskCount()); } +TEST_F(AccessCodeCastSinkServiceTest, TestFetchAndAddStoredDevices) { + // Test that ensures OpenChannels is called after valid sinks are fetched from + // the internal pref service. + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + const MediaSinkInternal cast_sink1 = CreateCastSink(1); + const MediaSinkInternal cast_sink2 = CreateCastSink(2); + const MediaSinkInternal cast_sink3 = CreateCastSink(3); + + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink1); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink2); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink3); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + std::vector<MediaSinkInternal> cast_sinks; + cast_sinks.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink1.id()) + .value()); + cast_sinks.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink2.id()) + .value()); + cast_sinks.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink3.id()) + .value()); + + EXPECT_CALL(*mock_cast_media_sink_service_impl(), + OpenChannels(cast_sinks, SinkSource::kAccessCode)) + .Times(1); + + mock_time_task_runner()->PostNonNestableDelayedTask( + FROM_HERE, + base::BindOnce( + &DiscoveryNetworkMonitor::GetNetworkId, + base::Unretained(discovery_network_monitor_.get()), + base::BindOnce(&AccessCodeCastSinkService::FetchAndAddStoredDevices, + access_code_cast_sink_service_->GetWeakPtr())), + base::Seconds(0)); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); +} + +TEST_F(AccessCodeCastSinkServiceTest, TestChangeNetworks) { + // Test that ensures sinks are stored on a network and then reopened when we + // connect back to that network. + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + const MediaSinkInternal cast_sink1 = CreateCastSink(1); + const MediaSinkInternal cast_sink2 = CreateCastSink(2); + const MediaSinkInternal cast_sink3 = CreateCastSink(3); + + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink1); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink2); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink3); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + std::vector<MediaSinkInternal> cast_sinks_ethernet; + cast_sinks_ethernet.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink1.id()) + .value()); + cast_sinks_ethernet.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink2.id()) + .value()); + cast_sinks_ethernet.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink3.id()) + .value()); + + EXPECT_CALL(*mock_cast_media_sink_service_impl(), + OpenChannels(cast_sinks_ethernet, SinkSource::kAccessCode)) + .Times(1); + + mock_time_task_runner()->PostNonNestableDelayedTask( + FROM_HERE, + base::BindOnce( + &DiscoveryNetworkMonitor::GetNetworkId, + base::Unretained(discovery_network_monitor_.get()), + base::BindOnce(&AccessCodeCastSinkService::FetchAndAddStoredDevices, + access_code_cast_sink_service_->GetWeakPtr())), + base::Seconds(0)); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + // Connect to a new network with different sinks. + fake_network_info_.clear(); + ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_NONE); + content::RunAllTasksUntilIdle(); + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + + fake_network_info_ = fake_wifi_info_; + ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_WIFI); + content::RunAllTasksUntilIdle(); + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + + const MediaSinkInternal cast_sink4 = CreateCastSink(4); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink4); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + std::vector<MediaSinkInternal> cast_sinks_wifi; + cast_sinks_wifi.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink4.id()) + .value()); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + EXPECT_CALL(*mock_cast_media_sink_service_impl(), + OpenChannels(cast_sinks_wifi, SinkSource::kAccessCode)) + .Times(1); + + mock_time_task_runner()->PostNonNestableDelayedTask( + FROM_HERE, + base::BindOnce( + &DiscoveryNetworkMonitor::GetNetworkId, + base::Unretained(discovery_network_monitor_.get()), + base::BindOnce(&AccessCodeCastSinkService::FetchAndAddStoredDevices, + access_code_cast_sink_service_->GetWeakPtr())), + base::Seconds(0)); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + // Reconnecting to the previous ethernet network should restore the same sinks + // from the cache and attempt to resolve them. + fake_network_info_.clear(); + ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_NONE); + content::RunAllTasksUntilIdle(); + mock_time_task_runner_->FastForwardUntilNoTasksRemain(); + + EXPECT_CALL(*mock_cast_media_sink_service_impl(), + OpenChannels(cast_sinks_ethernet, SinkSource::kAccessCode)) + .Times(1); + + fake_network_info_ = fake_ethernet_info_; + ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET); + content::RunAllTasksUntilIdle(); + mock_time_task_runner_->FastForwardUntilNoTasksRemain(); +} + +TEST_F(AccessCodeCastSinkServiceTest, + TestAddInvalidDevicesNoMediaSinkInternal) { + // Test that to check that if a sink is not stored in each pref, it will be + // removed from the pref service and no call to open channels is made. + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + const MediaSinkInternal cast_sink1 = CreateCastSink(1); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink1); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + std::vector<MediaSinkInternal> cast_sinks; + cast_sinks.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink1.id()) + .value()); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + // Remove the cast sink from the devices dict -- now the cast sink is + // incompletely stored since it only exists in 2/3 of the prefs. + access_code_cast_sink_service_->pref_updater_->RemoveSinkIdFromDevicesDict( + cast_sink1.id()); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + + base::Value::List sink_ids; + sink_ids.Append(cast_sink1.id()); + + EXPECT_CALL(*mock_cast_media_sink_service_impl(), + OpenChannels(cast_sinks, SinkSource::kAccessCode)) + .Times(0); + + EXPECT_FALSE( + access_code_cast_sink_service_->pref_updater_->GetDiscoveredNetworksDict() + ->GetDict() + .empty()); + EXPECT_FALSE( + access_code_cast_sink_service_->pref_updater_->GetDeviceAdditionTimeDict() + ->GetDict() + .empty()); + EXPECT_TRUE(access_code_cast_sink_service_->pref_updater_->GetDevicesDict() + ->GetDict() + .empty()); + + // Expect that the sink id is removed from all instance in the pref service. + access_code_cast_sink_service_->AddStoredDevicesToMediaRouter(sink_ids); + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + EXPECT_TRUE( + access_code_cast_sink_service_->pref_updater_->GetDiscoveredNetworksDict() + ->GetDict() + .empty()); + EXPECT_TRUE( + access_code_cast_sink_service_->pref_updater_->GetDeviceAdditionTimeDict() + ->GetDict() + .empty()); + EXPECT_TRUE(access_code_cast_sink_service_->pref_updater_->GetDevicesDict() + ->GetDict() + .empty()); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); +} + +TEST_F(AccessCodeCastSinkServiceTest, TestFetchAndAddStoredDevicesNoNetwork) { + // Test that to check that if a sink is not stored on the network, it won't + // attempted to be added. In this case no sink_ids should be removed. + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + const MediaSinkInternal cast_sink1 = CreateCastSink(1); + access_code_cast_sink_service_->StoreSinkInPrefs(&cast_sink1); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + std::vector<MediaSinkInternal> cast_sinks; + cast_sinks.push_back( + access_code_cast_sink_service_->ValidateDeviceFromSinkId(cast_sink1.id()) + .value()); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); + + // Remove the cast sink from the networks dict -- now the cast sink is + // incompletely stored since it only exists in 2/3 of the prefs. + access_code_cast_sink_service_->pref_updater_ + ->RemoveSinkIdFromDiscoveredNetworksDict(cast_sink1.id()); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + + EXPECT_CALL(*mock_cast_media_sink_service_impl(), + OpenChannels(cast_sinks, SinkSource::kAccessCode)) + .Times(0); + EXPECT_TRUE( + access_code_cast_sink_service_->pref_updater_->GetDiscoveredNetworksDict() + ->GetDict() + .empty()); + EXPECT_FALSE( + access_code_cast_sink_service_->pref_updater_->GetDeviceAdditionTimeDict() + ->GetDict() + .empty()); + EXPECT_FALSE(access_code_cast_sink_service_->pref_updater_->GetDevicesDict() + ->GetDict() + .empty()); + + mock_time_task_runner()->PostNonNestableDelayedTask( + FROM_HERE, + base::BindOnce( + &DiscoveryNetworkMonitor::GetNetworkId, + base::Unretained(discovery_network_monitor_.get()), + base::BindOnce(&AccessCodeCastSinkService::FetchAndAddStoredDevices, + access_code_cast_sink_service_->GetWeakPtr())), + base::Seconds(0)); + + mock_time_task_runner()->FastForwardUntilNoTasksRemain(); + task_environment_.RunUntilIdle(); +} + } // namespace media_router
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor.h b/chrome/browser/media/router/discovery/discovery_network_monitor.h index 47c30ff..09bb407 100644 --- a/chrome/browser/media/router/discovery/discovery_network_monitor.h +++ b/chrome/browser/media/router/discovery/discovery_network_monitor.h
@@ -72,6 +72,7 @@ private: friend class CastMediaSinkServiceImplTest; friend class DiscoveryNetworkMonitorTest; + friend class AccessCodeCastSinkServiceTest; friend struct std::default_delete<DiscoveryNetworkMonitor>; friend struct base::LazyInstanceTraitsBase<DiscoveryNetworkMonitor>;
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager_builder.cc b/chrome/browser/policy/cloud/user_cloud_policy_manager_builder.cc deleted file mode 100644 index e1a8d824..0000000 --- a/chrome/browser/policy/cloud/user_cloud_policy_manager_builder.cc +++ /dev/null
@@ -1,54 +0,0 @@ -// 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/policy/cloud/user_cloud_policy_manager_builder.h" - -#include <utility> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/policy/core/common/cloud/cloud_external_data_manager.h" -#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" -#include "components/policy/core/common/cloud/user_cloud_policy_store.h" -#include "content/public/browser/network_service_instance.h" - -namespace { - -// Directory inside the profile directory where policy-related resources are -// stored. -const base::FilePath::CharType kPolicy[] = FILE_PATH_LITERAL("Policy"); - -// Directory under kPolicy, in the user's profile dir, where policy for -// components is cached. -const base::FilePath::CharType kComponentsDir[] = - FILE_PATH_LITERAL("Components"); - -} // namespace - -namespace policy { - -std::unique_ptr<UserCloudPolicyManager> CreateUserCloudPolicyManager( - const base::FilePath& profile_path, - SchemaRegistry* schema_registry, - bool force_immediate_load, - const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) { - std::unique_ptr<UserCloudPolicyStore> store( - UserCloudPolicyStore::Create(profile_path, background_task_runner)); - if (force_immediate_load) - store->LoadImmediately(); - - const base::FilePath component_policy_cache_dir = - profile_path.Append(kPolicy).Append(kComponentsDir); - - auto policy_manager = std::make_unique<UserCloudPolicyManager>( - std::move(store), component_policy_cache_dir, - std::unique_ptr<CloudExternalDataManager>(), - base::ThreadTaskRunnerHandle::Get(), - base::BindRepeating(&content::GetNetworkConnectionTracker)); - policy_manager->Init(schema_registry); - return policy_manager; -} - -} // namespace policy
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager_builder.h b/chrome/browser/policy/cloud/user_cloud_policy_manager_builder.h deleted file mode 100644 index d1bd6f2..0000000 --- a/chrome/browser/policy/cloud/user_cloud_policy_manager_builder.h +++ /dev/null
@@ -1,29 +0,0 @@ -// 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 CHROME_BROWSER_POLICY_CLOUD_USER_CLOUD_POLICY_MANAGER_BUILDER_H_ -#define CHROME_BROWSER_POLICY_CLOUD_USER_CLOUD_POLICY_MANAGER_BUILDER_H_ - -#include <memory> - -#include "base/memory/scoped_refptr.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace policy { -class SchemaRegistry; -class UserCloudPolicyManager; - -std::unique_ptr<UserCloudPolicyManager> CreateUserCloudPolicyManager( - const base::FilePath& profile_path, - SchemaRegistry* schema_registry, - bool force_immediate_load, - const scoped_refptr<base::SequencedTaskRunner>& background_task_runner); - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_CLOUD_USER_CLOUD_POLICY_MANAGER_BUILDER_H_
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc index dfc2f0f..484e19d0 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -222,7 +222,7 @@ } bool UserPolicySigninService::CanApplyPolicies(bool check_for_refresh_token) { - if (!CanApplyPoliciesForSignedInUser(check_for_refresh_token, + if (!CanApplyPoliciesForSignedInUser(check_for_refresh_token, consent_level(), identity_manager())) { return false; }
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc index a9a28a5..39499a9c 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
@@ -14,6 +14,7 @@ #include "chrome/common/pref_names.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -87,7 +88,7 @@ void UserPolicySigninServiceFactory::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* user_prefs) { #if BUILDFLAG(IS_ANDROID) - user_prefs->RegisterInt64Pref(prefs::kLastPolicyCheckTime, 0); + user_prefs->RegisterInt64Pref(policy_prefs::kLastPolicyCheckTime, 0); #endif }
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc index 8a6a957..1883034 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc
@@ -28,6 +28,7 @@ #include "components/policy/core/browser/cloud/user_policy_signin_service_util.h" #include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/policy/core/common/policy_switches.h" #include "components/policy/proto/device_management_backend.pb.h" #include "components/prefs/pref_service.h" @@ -121,7 +122,7 @@ } bool UserPolicySigninService::CanApplyPolicies(bool check_for_refresh_token) { - if (!CanApplyPoliciesForSignedInUser(check_for_refresh_token, + if (!CanApplyPoliciesForSignedInUser(check_for_refresh_token, consent_level(), identity_manager())) { return false; } @@ -140,7 +141,7 @@ } base::Time last_check_time = base::Time::FromInternalValue( - profile_prefs_->GetInt64(prefs::kLastPolicyCheckTime)); + profile_prefs_->GetInt64(policy_prefs::kLastPolicyCheckTime)); base::Time next_check_time = last_check_time + retry_delay; // Check immediately if no check was ever done before (last_check_time == 0), @@ -156,7 +157,7 @@ void UserPolicySigninService::UpdateLastPolicyCheckTime() { // Persist the current time as the last policy registration attempt time. - profile_->GetPrefs()->SetInt64(prefs::kLastPolicyCheckTime, + profile_->GetPrefs()->SetInt64(policy_prefs::kLastPolicyCheckTime, base::Time::Now().ToInternalValue()); }
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc index b9cda1a..9b16c838 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -344,6 +344,9 @@ ASSERT_FALSE(manager_->core()->service()); } +// TODO(crbug.com/1312544): Extend the test coverage by merging tests from +// ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm here. + #if !BUILDFLAG(IS_ANDROID) TEST_F(UserPolicySigninServiceTest, InitRefreshTokenAvailableBeforeSignin) { // Make sure user is not signed in.
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index e2d76eb..a3d0830 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -166,6 +166,7 @@ #include "content/public/browser/federated_identity_api_permission_context_delegate.h" #include "content/public/browser/federated_identity_request_permission_context_delegate.h" #include "content/public/browser/federated_identity_sharing_permission_context_delegate.h" +#include "content/public/browser/network_service_instance.h" #include "content/public/browser/permission_controller.h" #include "content/public/browser/permission_type.h" #include "content/public/browser/render_process_host.h" @@ -204,8 +205,6 @@ #include "components/session_manager/core/session_manager.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" -#else -#include "chrome/browser/policy/cloud/user_cloud_policy_manager_builder.h" #endif #if BUILDFLAG(IS_ANDROID) @@ -600,9 +599,10 @@ #else { #endif // BUILDFLAG(IS_CHROMEOS_LACROS) - user_cloud_policy_manager_ = CreateUserCloudPolicyManager( + user_cloud_policy_manager_ = policy::UserCloudPolicyManager::Create( GetPath(), GetPolicySchemaRegistryService()->registry(), - force_immediate_policy_load, io_task_runner_); + force_immediate_policy_load, io_task_runner_, + base::BindRepeating(&content::GetNetworkConnectionTracker)); user_cloud_policy_manager = user_cloud_policy_manager_.get(); policy_provider = user_cloud_policy_manager; }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/chromevox.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/chromevox.js index 11868b2..76c6238 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/chromevox.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/chromevox.js
@@ -21,8 +21,6 @@ goog.require('constants'); ChromeVox = class { - constructor() {} - /** * Returns whether sticky mode is on, taking both the global sticky mode * pref and the temporary sticky mode override into account. @@ -101,18 +99,6 @@ * @type {Object<string, constants.Point>} */ ChromeVox.position = {}; -/** - * @type {string} - */ -ChromeVox.modKeyStr = 'Search'; -/** - * If any of these keys is pressed with the modifier key, we go in sequence mode - * where the subsequent independent key downs (while modifier keys are down) - * are a part of the same shortcut. - * @type {!Array<KeySequence>} - */ -ChromeVox.sequenceSwitchKeyCodes = []; - /** * Shortcut for document.getElementById.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js index 8a51775..600ba50 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js
@@ -7,13 +7,10 @@ * by the user. */ - goog.provide('KeySequence'); -goog.require('ChromeVox'); goog.require('KeyCode'); - /** * A class to represent a sequence of keys entered by a user or affiliated with * a ChromeVox command. @@ -218,7 +215,7 @@ // TODO (rshearer): This is a hack. When the modifier key becomes // customizable then we will not have to deal with strings here. - const modifierKeyCombo = ChromeVox.modKeyStr.split(/\+/g); + const modifierKeyCombo = KeySequence.modKeyStr.split(/\+/g); const index = this.keys.keyCode.length - 1; // For each modifier that is part of the CVox modifier, remove it from keys. @@ -311,7 +308,7 @@ */ isCVoxModifierActive(keyEvent) { // TODO (rshearer): Update this when the modifier key becomes customizable - let modifierKeyCombo = ChromeVox.modKeyStr.split(/\+/g); + let modifierKeyCombo = KeySequence.modKeyStr.split(/\+/g); // For each modifier that is held down, remove it from the combo. // If the combo string becomes empty, then the user has activated the combo. @@ -420,7 +417,7 @@ sequenceObject.doubleTap, skipStripping, sequenceObject.requireStickyMode); if (secondKeyPressed) { - ChromeVox.sequenceSwitchKeyCodes.push( + KeySequence.sequenceSwitchKeyCodes.push( new KeySequence(firstSequenceEvent, sequenceObject.cvoxModifier)); keySeq.addKeyEvent(secondSequenceEvent); } @@ -555,3 +552,14 @@ * @type {!Array<KeySequence>} */ KeySequence.doubleTapCache = []; + +/** + * If any of these keys is pressed with the modifier key, we go in sequence mode + * where the subsequent independent key downs (while modifier keys are down) + * are a part of the same shortcut. + * @public {!Array<KeySequence>} + */ +KeySequence.sequenceSwitchKeyCodes = []; + +/** @public {string} */ +KeySequence.modKeyStr = 'Search';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js index 25aaa61..6c4429be 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js
@@ -69,7 +69,7 @@ setUp() { super.setUp(); // Set up mock ChromeVox modifier - ChromeVox.modKeyStr = 'Alt'; + KeySequence.modKeyStr = 'Alt'; // Use these mock events in the tests: @@ -467,7 +467,7 @@ TEST_F( 'ChromeVoxKeySequenceUnitTest', 'DeserializeAltShiftCvoxMod', function() { - ChromeVox.modKeyStr = 'Alt+Shift'; + KeySequence.modKeyStr = 'Alt+Shift'; // Build a key sequence that does not strip modifiers when deserializing. // This feature is important for sequences that contain part or all of the @@ -491,7 +491,7 @@ // runtime both contain the bare cvox modifier as a key code such as in the // case of the Search sticky key and Search cvox modifier. Stripping happens // by default for key events at runtime. - ChromeVox.modKeyStr = 'Search'; + KeySequence.modKeyStr = 'Search'; // First, assert that unstripped seqs imply various modifier fields get set. let stickySeq = KeySequence.deserialize({keys: {keyCode: [KeyCode.SEARCH]}});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_util.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_util.js index a3c18a8c..1baad2a 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_util.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_util.js
@@ -145,7 +145,7 @@ * @return {Array<number>} Array of key codes. */ static cvoxModKeyCodes() { - const modKeyCombo = ChromeVox.modKeyStr.split(/\+/g); + const modKeyCombo = KeySequence.modKeyStr.split(/\+/g); const modKeyCodes = modKeyCombo.map(function(keyString) { return KeyUtil.modStringToKeyCode(keyString); }); @@ -155,14 +155,14 @@ /** * Checks if the specified key code is a key used for switching into a * sequence mode. Sequence switch keys are specified in - * KeyUtil.sequenceSwitchKeyCodes + * KeySequence.sequenceSwitchKeyCodes * * @param {!KeySequence} rhKeySeq The key sequence to check. * @return {boolean} true if it is a sequence switch keycode, false otherwise. */ static isSequenceSwitchKeyCode(rhKeySeq) { - for (let i = 0; i < ChromeVox.sequenceSwitchKeyCodes.length; i++) { - const lhKeySeq = ChromeVox.sequenceSwitchKeyCodes[i]; + for (let i = 0; i < KeySequence.sequenceSwitchKeyCodes.length; i++) { + const lhKeySeq = KeySequence.sequenceSwitchKeyCodes[i]; if (lhKeySeq.equals(rhKeySeq)) { return true; }
diff --git a/chrome/browser/resources/chromeos/assistant_optin/BUILD.gn b/chrome/browser/resources/chromeos/assistant_optin/BUILD.gn index 3007aef9..6f416bd 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/BUILD.gn +++ b/chrome/browser/resources/chromeos/assistant_optin/BUILD.gn
@@ -76,8 +76,6 @@ "assistant_loading.js", "assistant_optin_flow.html", "assistant_optin_flow.js", - "assistant_optin.html", - "assistant_optin.js", "assistant_related_info.html", "assistant_related_info.js", "assistant_value_prop.html",
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_common_styles.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_common_styles.html index 49d942ea..08eae80 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_common_styles.html +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_common_styles.html
@@ -1,6 +1,6 @@ -/* 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. */ +<!-- 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. --> <dom-module id="assistant-common-styles"> <template>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html index 5c2d319..8e55c16 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
@@ -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 srd="assistant_common_styles.html"> +<include src="assistant_common_styles.html"> <include src="assistant_loading.html"> <include src="assistant_related_info.html"> <include src="assistant_value_prop.html">
diff --git a/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd b/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd index cb72f7e..3b443ce 100644 --- a/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd +++ b/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd
@@ -25,6 +25,9 @@ <structure name="IDR_OOBE_DEBUGGER_UTIL_JS" file="debug\debug_util.js" type="chrome_html" flattenhtml="true" /> <structure name="IDR_KEYBOARD_UTILS_FOR_INJECTION_JS" file="components/keyboard_utils_for_injection.js" flattenhtml="true" type="chrome_html" /> + + <structure name="IDR_ASSISTANT_OPTIN_HTML" file="..\assistant_optin\assistant_optin.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" /> + <structure name="IDR_ASSISTANT_OPTIN_JS" file="..\assistant_optin\assistant_optin.js" flattenhtml="true" allowexternalscript="true" type="chrome_html" /> </structures> <includes> <!-- Resources that are served under fixed paths -->
diff --git a/chrome/browser/resources/feedback_webui/js/feedback.ts b/chrome/browser/resources/feedback_webui/js/feedback.ts index 8b94815..3abda09 100644 --- a/chrome/browser/resources/feedback_webui/js/feedback.ts +++ b/chrome/browser/resources/feedback_webui/js/feedback.ts
@@ -136,11 +136,11 @@ /** * Regular expression to check for all variants of blu[e]toot[h] with or without * space between the words; for BT when used as an individual word, or as two - * individual characters, and for BLE when used as an individual word. Case - * insensitive matching. + * individual characters, and for BLE, BlueZ, and Floss when used as an + * individual word. Case insensitive matching. */ -const btRegEx: RegExp = - new RegExp('blu[e]?[ ]?toot[h]?|\\bb[ ]?t\\b|\\bble\\b', 'i'); +const btRegEx: RegExp = new RegExp( + 'blu[e]?[ ]?toot[h]?|\\bb[ ]?t\\b|\\bble\\b|\\bfloss\\b|\\bbluez\\b', 'i'); /** * Regular expression to check for wifi-related keywords. @@ -197,6 +197,12 @@ const fastPairRegEx: RegExp = new RegExp('fast[ ]?pair', 'i'); /** + * Regular expression to check for Bluetooth device specific keywords. + */ +const btDeviceRegEx = + buildWordMatcher(['apple', 'allegro', 'pixelbud', 'microsoft', 'sony']); + +/** * Reads the selected file when the user selects a file. * @param fileSelectedEvent The onChanged event for the file input box. */ @@ -288,7 +294,7 @@ const isRelatedToBluetooth = btRegEx.test(value) || cantConnectRegEx.test(value) || tetherRegEx.test(value) || smartLockRegEx.test(value) || nearbyShareRegEx.test(value) || - fastPairRegEx.test(value); + fastPairRegEx.test(value) || btDeviceRegEx.test(value); $('bluetooth-checkbox-container').hidden = !isRelatedToBluetooth; }
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 47890cec..0fdd724 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -429,6 +429,7 @@ "//components/keyed_service/content", "//components/prefs", "//components/safe_browsing/core/browser:verdict_cache_manager", + "//components/safe_browsing/core/browser/sync", "//content/public/browser", ] }
diff --git a/chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_unittest.cc b/chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_unittest.cc index aad2aef2..02e600f 100644 --- a/chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_unittest.cc
@@ -80,7 +80,9 @@ false /* store_last_modified */, false /* restore_session */); cache_manager_ = std::make_unique<VerdictCacheManager>( - nullptr, content_setting_map_.get(), &test_pref_service_); + /*history_service=*/nullptr, content_setting_map_.get(), + &test_pref_service_, + /*sync_observer=*/nullptr); referrer_chain_provider_ = std::make_unique<MockReferrerChainProvider>(); TestingProfile::Builder builder;
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc index fc7eb34..474e4960 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -272,7 +272,7 @@ /*store_last_modified=*/false, /*restore_session=*/false); cache_manager_ = std::make_unique<VerdictCacheManager>( - nullptr, content_setting_map_.get(), &test_pref_service_); + nullptr, content_setting_map_.get(), &test_pref_service_, nullptr); service_ = NewMockPasswordProtectionService(); fake_user_event_service_ = static_cast<syncer::FakeUserEventService*>(
diff --git a/chrome/browser/safe_browsing/verdict_cache_manager_factory.cc b/chrome/browser/safe_browsing/verdict_cache_manager_factory.cc index e94e9c3..be6a9534 100644 --- a/chrome/browser/safe_browsing/verdict_cache_manager_factory.cc +++ b/chrome/browser/safe_browsing/verdict_cache_manager_factory.cc
@@ -9,7 +9,9 @@ #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/sync_service_factory.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/safe_browsing/core/browser/sync/safe_browsing_sync_observer_impl.h" #include "components/safe_browsing/core/browser/verdict_cache_manager.h" #include "content/public/browser/browser_context.h" @@ -33,6 +35,7 @@ BrowserContextDependencyManager::GetInstance()) { DependsOn(HistoryServiceFactory::GetInstance()); DependsOn(HostContentSettingsMapFactory::GetInstance()); + DependsOn(SyncServiceFactory::GetInstance()); } KeyedService* VerdictCacheManagerFactory::BuildServiceInstanceFor( @@ -42,7 +45,9 @@ HistoryServiceFactory::GetForProfile(profile, ServiceAccessType::EXPLICIT_ACCESS), HostContentSettingsMapFactory::GetForProfile(profile), - profile->GetPrefs()); + profile->GetPrefs(), + std::make_unique<SafeBrowsingSyncObserverImpl>( + SyncServiceFactory::GetForProfile(profile))); } content::BrowserContext* VerdictCacheManagerFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/startup_data.cc b/chrome/browser/startup_data.cc index 267d17c..8357ef0 100644 --- a/chrome/browser/startup_data.cc +++ b/chrome/browser/startup_data.cc
@@ -19,10 +19,10 @@ #include "third_party/metrics_proto/system_profile.pb.h" #if BUILDFLAG(IS_ANDROID) +#include "base/bind.h" #include "base/files/file_util.h" #include "base/path_service.h" #include "chrome/browser/android/profile_key_startup_accessor.h" -#include "chrome/browser/policy/cloud/user_cloud_policy_manager_builder.h" #include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/policy/profile_policy_connector_builder.h" #include "chrome/browser/policy/schema_registry_service.h" @@ -179,9 +179,10 @@ std::move(schema_registry), browser_policy_connector->GetChromeSchema(), browser_policy_connector->GetSchemaRegistry()); - user_cloud_policy_manager_ = CreateUserCloudPolicyManager( + user_cloud_policy_manager_ = policy::UserCloudPolicyManager::Create( path, schema_registry_service_->registry(), - true /* force_immediate_policy_load */, io_task_runner); + true /* force_immediate_policy_load */, io_task_runner, + base::BindRepeating(&content::GetNetworkConnectionTracker)); profile_policy_connector_ = policy::CreateAndInitProfilePolicyConnector( schema_registry_service_->registry(),
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index d83393f3..7f5b71b 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1135,6 +1135,8 @@ "media_router/cast_modes_with_media_sources.h", "media_router/media_cast_mode.cc", "media_router/media_cast_mode.h", + "media_router/media_route_starter.cc", + "media_router/media_route_starter.h", "media_router/media_router_ui.cc", "media_router/media_router_ui.h", "media_router/media_router_ui_helper.cc", @@ -1145,10 +1147,12 @@ "media_router/media_router_ui_service_factory.h", "media_router/media_sink_with_cast_modes.cc", "media_router/media_sink_with_cast_modes.h", + "media_router/media_sink_with_cast_modes_observer.h", "media_router/presentation_receiver_window.h", "media_router/presentation_receiver_window_controller.cc", "media_router/presentation_receiver_window_controller.h", "media_router/presentation_receiver_window_delegate.h", + "media_router/presentation_request_source_observer.h", "media_router/query_result_manager.cc", "media_router/query_result_manager.h", "media_router/ui_media_sink.cc",
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc index a87ae97..8b2972d1 100644 --- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc +++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -297,16 +297,6 @@ Release(key, modifiers); } - // TODO(crbug.com/1304484): Check whether this currently unused function - // should have been used or if it can be deleted. - void WaitUntilItemDeletionCompletes() { - auto* context_menu = GetContextMenu(); - DCHECK(context_menu); - base::RunLoop run_loop; - context_menu->set_item_removal_callback_for_test(run_loop.QuitClosure()); - run_loop.Run(); - } - void ShowContextMenuViaAccelerator(bool wait_for_selection) { PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN); if (!wait_for_selection) @@ -322,14 +312,6 @@ return GetContextMenu()->GetMenuItemViewAtForTest(index); } - // TODO(crbug.com/1304484): Check whether this currently unused function - // should have been used or if it can be deleted. - views::MenuItemView* GetMenuItemViewForTest(int index) { - return const_cast<views::MenuItemView*>( - const_cast<const ClipboardHistoryBrowserTest*>(this) - ->GetMenuItemViewForIndex(index)); - } - const ash::ClipboardHistoryItemView* GetHistoryItemViewForIndex( int index) const { const views::MenuItemView* hosting_menu_item =
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc index 3493b718..30dc273 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -210,6 +210,12 @@ return popup_host_ != nullptr; } +bool ExtensionActionViewController::IsRequestingSiteAccess( + content::WebContents* web_contents) const { + return GetSiteInteraction(web_contents) == + extensions::SitePermissionsHelper::SiteInteraction::kPending; +} + void ExtensionActionViewController::HidePopup() { if (IsShowingPopup()) { popup_host_->Close();
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.h b/chrome/browser/ui/extensions/extension_action_view_controller.h index 487d6599..7248884 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.h +++ b/chrome/browser/ui/extensions/extension_action_view_controller.h
@@ -73,6 +73,8 @@ content::WebContents* web_contents) const override; bool IsEnabled(content::WebContents* web_contents) const override; bool IsShowingPopup() const override; + bool IsRequestingSiteAccess( + content::WebContents* web_contents) const override; void HidePopup() override; gfx::NativeView GetPopupNativeView() override; ui::MenuModel* GetContextMenu(
diff --git a/chrome/browser/ui/focus_tab_after_navigation_helper.cc b/chrome/browser/ui/focus_tab_after_navigation_helper.cc index 9e68b57..5458a8a 100644 --- a/chrome/browser/ui/focus_tab_after_navigation_helper.cc +++ b/chrome/browser/ui/focus_tab_after_navigation_helper.cc
@@ -48,9 +48,6 @@ return false; // Don't focus content after subframe navigations. - // TODO(https://crbug.com/1218946): With MPArch there may be multiple main - // frames. This caller was converted automatically to the primary main frame - // to preserve its semantics. Follow up to confirm correctness. if (!navigation->IsInPrimaryMainFrame()) return false;
diff --git a/chrome/browser/ui/intent_picker_tab_helper.cc b/chrome/browser/ui/intent_picker_tab_helper.cc index d23a90a..2da630d 100644 --- a/chrome/browser/ui/intent_picker_tab_helper.cc +++ b/chrome/browser/ui/intent_picker_tab_helper.cc
@@ -5,12 +5,14 @@ #include "chrome/browser/ui/intent_picker_tab_helper.h" #include <utility> +#include <vector> #include "base/bind.h" #include "base/feature_list.h" #include "build/build_config.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/intent_helper/apps_navigation_types.h" #include "chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h" #include "chrome/browser/apps/intent_helper/intent_picker_features.h" #include "chrome/browser/apps/intent_helper/intent_picker_helpers.h" @@ -18,9 +20,11 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" #include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/icon_types.h" #include "content/public/browser/navigation_handle.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/models/image_model.h" @@ -68,38 +72,61 @@ return provider ? &provider->install_manager() : nullptr; } +void LoadSingleAppIcon(Profile* profile, + apps::mojom::AppType app_type, + const std::string& app_id, + int size_in_dip, + base::OnceCallback<void(apps::IconValuePtr)> callback) { + constexpr bool allow_placeholder_icon = false; + if (base::FeatureList::IsEnabled(features::kAppServiceLoadIconWithoutMojom)) { + apps::AppServiceProxyFactory::GetForProfile(profile)->LoadIcon( + apps::ConvertMojomAppTypToAppType(app_type), app_id, + apps::IconType::kStandard, size_in_dip, allow_placeholder_icon, + std::move(callback)); + } else { + apps::AppServiceProxyFactory::GetForProfile(profile)->LoadIcon( + app_type, app_id, apps::mojom::IconType::kStandard, size_in_dip, + allow_placeholder_icon, + apps::MojomIconValueToIconValueCallback(std::move(callback))); + } +} + } // namespace IntentPickerTabHelper::~IntentPickerTabHelper() = default; // static -void IntentPickerTabHelper::SetShouldShowIcon( - content::WebContents* web_contents, - bool should_show_icon) { +void IntentPickerTabHelper::ShowOrHideIcon(content::WebContents* web_contents, + bool should_show_icon) { IntentPickerTabHelper* tab_helper = FromWebContents(web_contents); if (!tab_helper) return; + tab_helper->ShowOrHideIconInternal(should_show_icon); +} -#if BUILDFLAG(IS_CHROMEOS) - if (should_show_icon && !tab_helper->should_show_icon_) { - // This point doesn't exactly match when the icon is shown in the UI (e.g. - // if the tab is not active), but recording here corresponds more closely to - // navigations which cause the icon to appear. - apps::IntentHandlingMetrics::RecordIntentPickerIconEvent( - apps::IntentHandlingMetrics::IntentPickerIconEvent::kIconShown); - } -#endif +void IntentPickerTabHelper::ShowIconForApps( + const std::vector<apps::IntentPickerAppInfo>& apps) { + if (apps::features::AppIconInIntentChipEnabled()) { + if (apps.size() == 1 && apps[0].launch_name != last_shown_app_id_) { + const std::string& app_id = apps[0].launch_name; + auto app_type = GetAppType(apps[0].type); - tab_helper->should_show_icon_ = should_show_icon; + Profile* profile = + Profile::FromBrowserContext(web_contents()->GetBrowserContext()); - if (apps::features::LinkCapturingUiUpdateEnabled()) { - tab_helper->UpdateCollapsedState(); + last_shown_app_id_ = app_id; + LoadSingleAppIcon( + profile, app_type, app_id, GetLayoutConstant(LOCATION_BAR_ICON_SIZE), + base::BindOnce(&IntentPickerTabHelper::OnAppIconLoadedForChip, + weak_factory_.GetWeakPtr(), app_id)); + return; + } else if (apps.size() != 1) { + app_icon_ = ui::ImageModel(); + last_shown_app_id_ = std::string(); + } } - Browser* browser = chrome::FindBrowserWithWebContents(web_contents); - if (!browser) - return; - browser->window()->UpdatePageActionIcon(PageActionIconType::kIntentPicker); + ShowOrHideIconInternal(!apps.empty()); } IntentPickerTabHelper::IntentPickerTabHelper(content::WebContents* web_contents) @@ -124,6 +151,11 @@ tab_helper->LoadAppIcon(std::move(apps), std::move(callback), 0); } +void IntentPickerTabHelper::SetIconUpdateCallbackForTesting( + base::OnceClosure callback) { + icon_update_closure_ = std::move(callback); +} + void IntentPickerTabHelper::OnAppIconLoaded( std::vector<apps::IntentPickerAppInfo> apps, IntentPickerIconLoaderCallback callback, @@ -156,22 +188,10 @@ Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); - constexpr bool allow_placeholder_icon = false; - if (base::FeatureList::IsEnabled(features::kAppServiceLoadIconWithoutMojom)) { - apps::AppServiceProxyFactory::GetForProfile(profile)->LoadIcon( - apps::ConvertMojomAppTypToAppType(app_type), app_id, - apps::IconType::kStandard, gfx::kFaviconSize, allow_placeholder_icon, - base::BindOnce(&IntentPickerTabHelper::OnAppIconLoaded, - weak_factory_.GetWeakPtr(), std::move(apps), - std::move(callback), index)); - } else { - apps::AppServiceProxyFactory::GetForProfile(profile)->LoadIcon( - app_type, app_id, apps::mojom::IconType::kStandard, gfx::kFaviconSize, - allow_placeholder_icon, - apps::MojomIconValueToIconValueCallback(base::BindOnce( - &IntentPickerTabHelper::OnAppIconLoaded, weak_factory_.GetWeakPtr(), - std::move(apps), std::move(callback), index))); - } + LoadSingleAppIcon(profile, app_type, app_id, gfx::kFaviconSize, + base::BindOnce(&IntentPickerTabHelper::OnAppIconLoaded, + weak_factory_.GetWeakPtr(), std::move(apps), + std::move(callback), index)); } void IntentPickerTabHelper::UpdateCollapsedState() { @@ -198,6 +218,47 @@ } } +void IntentPickerTabHelper::OnAppIconLoadedForChip(const std::string& app_id, + apps::IconValuePtr icon) { + if (app_id != last_shown_app_id_) + return; + + if (icon && icon->icon_type == apps::IconType::kStandard) { + app_icon_ = ui::ImageModel::FromImage(gfx::Image(icon->uncompressed)); + } else { + last_shown_app_id_ = std::string(); + app_icon_ = ui::ImageModel(); + } + + ShowOrHideIconInternal(true); +} + +void IntentPickerTabHelper::ShowOrHideIconInternal(bool should_show_icon) { +#if BUILDFLAG(IS_CHROMEOS) + if (should_show_icon && !should_show_icon_) { + // This point doesn't exactly match when the icon is shown in the UI (e.g. + // if the tab is not active), but recording here corresponds more closely to + // navigations which cause the icon to appear. + apps::IntentHandlingMetrics::RecordIntentPickerIconEvent( + apps::IntentHandlingMetrics::IntentPickerIconEvent::kIconShown); + } +#endif + + should_show_icon_ = should_show_icon; + + if (apps::features::LinkCapturingUiUpdateEnabled()) { + UpdateCollapsedState(); + } + + Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); + if (!browser) + return; + browser->window()->UpdatePageActionIcon(PageActionIconType::kIntentPicker); + + if (icon_update_closure_) + std::move(icon_update_closure_).Run(); +} + void IntentPickerTabHelper::DidFinishNavigation( content::NavigationHandle* navigation_handle) { // For a http/https scheme URL navigation, we will check if the @@ -215,9 +276,11 @@ navigation_handle->GetPreviousMainFrameURL())) { bool is_valid_page = navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && !navigation_handle->IsErrorPage(); - bool should_show_icon = - is_valid_page && apps::MaybeShowIntentPicker(navigation_handle); - IntentPickerTabHelper::SetShouldShowIcon(web_contents(), should_show_icon); + if (is_valid_page) { + apps::MaybeShowIntentPicker(navigation_handle); + } else { + ShowOrHideIcon(web_contents(), /*should_show_icon=*/false); + } } } @@ -228,7 +291,7 @@ absl::optional<web_app::AppId> local_app_id = registrar_->FindAppWithUrlInScope(web_contents()->GetLastCommittedURL()); if (app_id == local_app_id) - SetShouldShowIcon(web_contents(), false); + ShowOrHideIcon(web_contents(), /*should_show_icon=*/false); } void IntentPickerTabHelper::OnWebAppInstallManagerDestroyed() {
diff --git a/chrome/browser/ui/intent_picker_tab_helper.h b/chrome/browser/ui/intent_picker_tab_helper.h index 27924a5..c4b896f 100644 --- a/chrome/browser/ui/intent_picker_tab_helper.h +++ b/chrome/browser/ui/intent_picker_tab_helper.h
@@ -7,7 +7,7 @@ #include <vector> -#include "base/callback.h" +#include "base/callback_forward.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" @@ -19,6 +19,7 @@ #include "components/services/app_service/public/mojom/types.mojom-forward.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +#include "ui/base/models/image_model.h" #include "url/origin.h" // Controls the visibility of IntentPickerView by updating the visibility based @@ -33,8 +34,13 @@ ~IntentPickerTabHelper() override; - static void SetShouldShowIcon(content::WebContents* web_contents, - bool should_show_icon); + // Shows or hides the intent picker icon for |web_contents|. + static void ShowOrHideIcon(content::WebContents* web_contents, + bool should_show_icon); + + // Shows or hides the intent picker icon for this tab based on the given + // |apps|. + void ShowIconForApps(const std::vector<apps::IntentPickerAppInfo>& apps); bool should_show_icon() const { return should_show_icon_; } @@ -42,6 +48,8 @@ return should_show_collapsed_chip_; } + const ui::ImageModel& app_icon() const { return app_icon_; } + using IntentPickerIconLoaderCallback = base::OnceCallback<void(std::vector<apps::IntentPickerAppInfo> apps)>; @@ -50,6 +58,10 @@ std::vector<apps::IntentPickerAppInfo> apps, IntentPickerIconLoaderCallback callback); + // Sets a OnceClosure callback which will be called next time the icon is + // updated. + void SetIconUpdateCallbackForTesting(base::OnceClosure callback); + WEB_CONTENTS_USER_DATA_KEY_DECL(); private: @@ -65,8 +77,12 @@ IntentPickerIconLoaderCallback callback, size_t index); + void OnAppIconLoadedForChip(const std::string& app_id, + apps::IconValuePtr icon); + void ShowOrHideIconInternal(bool should_show_icon); void UpdateCollapsedState(); + // content::WebContentsObserver: void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; @@ -81,6 +97,11 @@ url::Origin last_shown_origin_; bool should_show_collapsed_chip_ = false; + std::string last_shown_app_id_; + ui::ImageModel app_icon_; + + base::OnceClosure icon_update_closure_; + base::ScopedObservation<web_app::WebAppInstallManager, web_app::WebAppInstallManagerObserver> install_manager_observation_{this};
diff --git a/chrome/browser/ui/media_router/media_route_starter.cc b/chrome/browser/ui/media_router/media_route_starter.cc new file mode 100644 index 0000000..b946c02 --- /dev/null +++ b/chrome/browser/ui/media_router/media_route_starter.cc
@@ -0,0 +1,295 @@ +// Copyright 2022 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/media_router/media_route_starter.h" + +#include "base/containers/contains.h" +#include "base/strings/strcat.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/media_router/media_cast_mode.h" +#include "chrome/browser/ui/media_router/media_router_ui_helper.h" +#include "chrome/browser/ui/media_router/query_result_manager.h" +#include "chrome/grit/generated_resources.h" +#include "components/media_router/browser/issue_manager.h" +#include "components/media_router/browser/media_router.h" +#include "components/media_router/browser/media_router_factory.h" +#include "components/media_router/common/media_source.h" +#include "components/sessions/content/session_tab_helper.h" +#include "components/sessions/core/session_id.h" +#include "components/url_formatter/elide_url.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/presentation_request.h" +#include "content/public/browser/web_contents.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/constants.h" +#include "ui/base/l10n/l10n_util.h" + +#if BUILDFLAG(IS_MAC) +#include "base/mac/mac_util.h" +#include "ui/base/cocoa/permissions_utils.h" +#endif + +namespace media_router { + +namespace { +void RunRouteResponseCallbacks( + MediaRouteResponseCallback presentation_callback, + std::vector<MediaRouteResultCallback> route_result_callbacks, + mojom::RoutePresentationConnectionPtr connection, + const RouteRequestResult& result) { + if (presentation_callback) + std::move(presentation_callback).Run(std::move(connection), result); + DCHECK(!connection); + for (auto& callback : route_result_callbacks) + std::move(callback).Run(result); +} + +} // namespace + +MediaRouteStarter::MediaRouteStarter( + const CastModeSet& initial_modes, + content::WebContents* web_contents, + std::unique_ptr<StartPresentationContext> start_presentation_context) + : web_contents_(web_contents), + start_presentation_context_(std::move(start_presentation_context)), + presentation_manager_( + web_contents ? WebContentsPresentationManager::Get(web_contents) + : nullptr), + query_result_manager_( + std::make_unique<QueryResultManager>(GetMediaRouter())) { + if (presentation_manager_) + presentation_manager_->AddObserver(this); + InitPresentationSources(initial_modes); + InitMirroringSources(initial_modes); +} + +MediaRouteStarter::~MediaRouteStarter() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (presentation_manager_) + presentation_manager_->RemoveObserver(this); + + // If |start_presentation_context_| still exists, then it means presentation + // route request was never attempted. + if (start_presentation_context_) { + std::vector<MediaSinkWithCastModes> sinks = + GetQueryResultManager()->GetSinksWithCastModes(); + bool presentation_sinks_available = std::any_of( + sinks.begin(), sinks.end(), [](const MediaSinkWithCastModes& sink) { + return base::Contains(sink.cast_modes, MediaCastMode::PRESENTATION); + }); + if (presentation_sinks_available) { + start_presentation_context_->InvokeErrorCallback( + blink::mojom::PresentationError(blink::mojom::PresentationErrorType:: + PRESENTATION_REQUEST_CANCELLED, + "Dialog closed.")); + } else { + start_presentation_context_->InvokeErrorCallback( + blink::mojom::PresentationError( + blink::mojom::PresentationErrorType::NO_AVAILABLE_SCREENS, + "No screens found.")); + } + } +} + +void MediaRouteStarter::AddPresentationRequestSourceObserver( + PresentationRequestSourceObserver* observer) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(observer); + observers_.AddObserver(observer); +} + +void MediaRouteStarter::RemovePresentationRequestSourceObserver( + PresentationRequestSourceObserver* observer) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(observer); + observers_.RemoveObserver(observer); +} + +void MediaRouteStarter::AddMediaSinkWithCastModesObserver( + MediaSinkWithCastModesObserver* observer) { + GetQueryResultManager()->AddObserver(observer); +} + +void MediaRouteStarter::RemoveMediaSinkWithCastModesObserver( + MediaSinkWithCastModesObserver* observer) { + GetQueryResultManager()->RemoveObserver(observer); +} + +Profile* MediaRouteStarter::GetProfile() const { + return GetWebContents() && GetWebContents()->GetBrowserContext() + ? Profile::FromBrowserContext( + GetWebContents()->GetBrowserContext()) + : ProfileManager::GetActiveUserProfile(); +} + +MediaRouter* MediaRouteStarter::GetMediaRouter() const { + return MediaRouterFactory::GetApiForBrowserContext(GetProfile()); +} + +std::unique_ptr<RouteParameters> MediaRouteStarter::CreateRouteParameters( + const MediaSink::Id& sink_id, + MediaCastMode cast_mode) { + std::unique_ptr<RouteParameters> params = std::make_unique<RouteParameters>(); + + params->cast_mode = cast_mode; + + std::unique_ptr<MediaSource> source = + GetQueryResultManager()->GetSourceForCastModeAndSink(cast_mode, sink_id); + if (!source) { + return nullptr; + } + params->source_id = source->id(); + + bool for_presentation_source = cast_mode == MediaCastMode::PRESENTATION; + if (for_presentation_source && !presentation_request_) { + GetMediaRouter()->GetLogger()->LogError( + mojom::LogCategory::kUi, component_, + "Requested to create a route for presentation, but " + "presentation request is missing.", + sink_id, source->id(), ""); + return nullptr; + } + + params->request = std::make_unique<RouteRequest>(sink_id); + + params->origin = for_presentation_source ? presentation_request_->frame_origin + : url::Origin::Create(GURL()); + + params->timeout = GetRouteRequestTimeout(cast_mode); + params->off_the_record = + GetWebContents() && + GetWebContents()->GetBrowserContext()->IsOffTheRecord(); + + return params; +} + +bool MediaRouteStarter::GetScreenCapturePermission(MediaCastMode cast_mode) { + if (!RequiresScreenCapturePermission(cast_mode)) + return true; + + return media_router::GetScreenCapturePermission(); +} + +void MediaRouteStarter::StartRoute(std::unique_ptr<RouteParameters> params) { + DCHECK(params) << "Must have params!"; + DCHECK(params->request) << "Must have params->request!"; + DCHECK(!params->presentation_callback) + << "params->presentation_callback is not used!"; + + MediaRouteResponseCallback presentation_callback; + + if (params->cast_mode == MediaCastMode::PRESENTATION) { + if (start_presentation_context_) { + presentation_callback = + base::BindOnce(&StartPresentationContext::HandleRouteResponse, + std::move(start_presentation_context_)); + } else if (presentation_manager_) { + presentation_callback = base::BindOnce( + &WebContentsPresentationManager::OnPresentationResponse, + presentation_manager_, *presentation_request_); + } else { + NOTREACHED(); + } + } + + GetMediaRouter()->CreateRoute( + params->source_id, params->request->sink_id, params->origin, + GetWebContents(), + base::BindOnce(&RunRouteResponseCallbacks, + std::move(presentation_callback), + std::move(params->route_result_callbacks)), + params->timeout, params->off_the_record); +} + +std::u16string MediaRouteStarter::GetPresentationRequestSourceName() const { + const url::Origin frame_origin = GetFrameOrigin(); + // Presentation URLs are only possible on https: and other secure contexts, + // so we can omit http/https schemes here. + return frame_origin.scheme() == extensions::kExtensionScheme + ? base::UTF8ToUTF16(GetExtensionName( + frame_origin.GetURL(), + extensions::ExtensionRegistry::Get(GetBrowserContext()))) + : url_formatter::FormatOriginForSecurityDisplay( + frame_origin, + url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS); +} + +void MediaRouteStarter::OnDefaultPresentationChanged( + const content::PresentationRequest* presentation_request) { + if (presentation_request) { + std::vector<MediaSource> sources; + for (const auto& url : presentation_request->presentation_urls) { + sources.push_back(MediaSource::ForPresentationUrl(url)); + } + presentation_request_ = *presentation_request; + GetQueryResultManager()->SetSourcesForCastMode( + MediaCastMode::PRESENTATION, sources, + presentation_request_->frame_origin); + } else { + presentation_request_.reset(); + GetQueryResultManager()->RemoveSourcesForCastMode( + MediaCastMode::PRESENTATION); + } + + auto name = GetPresentationRequestSourceName(); + for (PresentationRequestSourceObserver& observer : observers_) { + observer.OnSourceUpdated(name); + } +} + +void MediaRouteStarter::InitPresentationSources( + const CastModeSet& initial_modes) { + if (!IsCastModeAvailable(initial_modes, MediaCastMode::PRESENTATION)) { + // No need to bother if presentation isn't an option. + return; + } + if (start_presentation_context_) { + OnDefaultPresentationChanged( + &start_presentation_context_->presentation_request()); + } else if (presentation_manager_ && + presentation_manager_->HasDefaultPresentationRequest()) { + OnDefaultPresentationChanged( + &presentation_manager_->GetDefaultPresentationRequest()); + } +} + +void MediaRouteStarter::InitMirroringSources(const CastModeSet& initial_modes) { + // Use a placeholder URL as origin for mirroring. + url::Origin origin = url::Origin::Create(GURL()); + + if (IsCastModeAvailable(initial_modes, MediaCastMode::DESKTOP_MIRROR)) { + GetQueryResultManager()->SetSourcesForCastMode( + MediaCastMode::DESKTOP_MIRROR, {MediaSource::ForUnchosenDesktop()}, + origin); + } + + if (IsCastModeAvailable(initial_modes, MediaCastMode::TAB_MIRROR)) { + SessionID::id_type tab_id = + sessions::SessionTabHelper::IdForTab(web_contents_).id(); + if (tab_id != -1) { + MediaSource mirroring_source(MediaSource::ForTab(tab_id)); + GetQueryResultManager()->SetSourcesForCastMode( + MediaCastMode::TAB_MIRROR, {mirroring_source}, origin); + } + } +} + +content::BrowserContext* MediaRouteStarter::GetBrowserContext() const { + return GetWebContents() ? GetWebContents()->GetBrowserContext() + : ProfileManager::GetActiveUserProfile(); +} + +url::Origin MediaRouteStarter::GetFrameOrigin() const { + return presentation_request_ ? presentation_request_->frame_origin + : url::Origin(); +} + +bool MediaRouteStarter::IsCastModeAvailable(const CastModeSet& modes, + MediaCastMode mode) { + return base::Contains(modes, mode); +} + +} // namespace media_router
diff --git a/chrome/browser/ui/media_router/media_route_starter.h b/chrome/browser/ui/media_router/media_route_starter.h new file mode 100644 index 0000000..95eacf4 --- /dev/null +++ b/chrome/browser/ui/media_router/media_route_starter.h
@@ -0,0 +1,165 @@ +// Copyright 2022 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_UI_MEDIA_ROUTER_MEDIA_ROUTE_STARTER_H_ +#define CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_ROUTE_STARTER_H_ + +#include <string> + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/media_router/media_cast_mode.h" +#include "chrome/browser/ui/media_router/media_router_ui_helper.h" +#include "chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h" +#include "chrome/browser/ui/media_router/presentation_request_source_observer.h" +#include "chrome/browser/ui/media_router/query_result_manager.h" +#include "components/media_router/browser/presentation/start_presentation_context.h" +#include "components/media_router/browser/presentation/web_contents_presentation_manager.h" +#include "components/media_router/common/issue.h" +#include "url/origin.h" + +namespace content { +class BrowserContext; +struct PresentationRequest; +class WebContents; +} // namespace content + +namespace media_router { +class MediaRouter; +class QueryResultManager; + +// Provides cast services (lists of sinks, routes, start & terminate route) to +// UI controllers +class MediaRouteStarter : public WebContentsPresentationManager::Observer { + public: + class Observer { + public: + virtual ~Observer() = default; + + virtual void OnPresentationRequestSourceUpdated( + std::u16string presentation_request_source_name) = 0; + }; + + MediaRouteStarter( + const CastModeSet& initial_modes, + content::WebContents* web_contents, + std::unique_ptr<StartPresentationContext> start_presentation_context); + MediaRouteStarter(const MediaRouteStarter&) = delete; + MediaRouteStarter& operator=(const MediaRouteStarter&) = delete; + + ~MediaRouteStarter() override; + + // Adds/removes an observer that is notified when the presentation request + // source is updated. + void AddPresentationRequestSourceObserver( + PresentationRequestSourceObserver* observer); + void RemovePresentationRequestSourceObserver( + PresentationRequestSourceObserver* observer); + + void AddMediaSinkWithCastModesObserver( + MediaSinkWithCastModesObserver* observer); + void RemoveMediaSinkWithCastModesObserver( + MediaSinkWithCastModesObserver* observer); + + content::WebContents* GetWebContents() const { return web_contents_; } + + // Returns the profile associated with this casting attempt. Will either be + // the profile associated with the browser containing the contentg being + // cast, or the active user profile in the case of desktop mirroring. + virtual Profile* GetProfile() const; + + // Returns the MediaRouter for this instance's BrowserContext. + virtual MediaRouter* GetMediaRouter() const; + + // Sets the component used for media router logging statements made by the + // MediaRouteStarter + void SetLoggerComponent(const std::string& component) { + component_ = component; + } + + // Constructs |RouteParameters| with the necessary information for + // |StartRoute| to construct a route between |sink_id| and an available source + // that supports |cast_mode|. The returned |RouteParameters| can be modified + // by the caller as desired, notably any callbacks that the caller wishes to + // have called on route creation shuold be added to + // |RouteParameters.route_result_callbacks|. + std::unique_ptr<RouteParameters> CreateRouteParameters( + const MediaSink::Id& sink_id, + MediaCastMode cast_mode); + + void StartRoute(std::unique_ptr<RouteParameters> params); + + // Returns a PresentationRequest source name that can be shown in the dialog. + std::u16string GetPresentationRequestSourceName() const; + + // Determines if the given cast mode requires user permission, and if so, + // obtains it. Will only be false if permission is required and user does not + // provide. + static bool GetScreenCapturePermission(MediaCastMode cast_mode); + + private: + friend class MediaRouteStarterTest; + FRIEND_TEST_ALL_PREFIXES(MediaRouteStarterTest, + OnPresentationRequestSourceRemoved); + FRIEND_TEST_ALL_PREFIXES(MediaRouteStarterTest, + OnPresentationRequestSourceUpdated); + FRIEND_TEST_ALL_PREFIXES(MediaRouteStarterTest, GetScreenCapturePermission); + + void InitPresentationSources(const CastModeSet& initial_modes); + void InitMirroringSources(const CastModeSet& initial_modes); + + content::BrowserContext* GetBrowserContext() const; + + // Returns the default PresentationRequest's frame origin if there is one. + // Otherwise returns an opaque origin. + url::Origin GetFrameOrigin() const; + + // Returns the QueryResultManager for this instance's |GetMediaRouter| + QueryResultManager* GetQueryResultManager() const { + return query_result_manager_.get(); + } + + // Returns true if the specified cast mode is among the cast modes specified + // as supported for the service when initialized. + static bool IsCastModeAvailable(const CastModeSet& modes, MediaCastMode mode); + + // WebContentsPresentationManager::Observer + void OnDefaultPresentationChanged( + const content::PresentationRequest* presentation_request) override; + + // Component name used for media router logging. + std::string component_ = "MediaRouteStarter"; + + // If set, this is the tab for which this casting request was initiated. May + // be null in the case of desktop tab casting. + const raw_ptr<content::WebContents> web_contents_; + + // If set, then the result of the next presentation route request will + // be handled by this object instead of |presentation_manager_| + std::unique_ptr<StartPresentationContext> start_presentation_context_; + + // |presentation_manager_| notifies |this| whenever there is an update to the + // default PresentationRequest or MediaRoutes associated with |web_contents_|. + base::WeakPtr<WebContentsPresentationManager> presentation_manager_; + + // Monitors and reports sink availability. + std::unique_ptr<QueryResultManager> query_result_manager_; + + // Set to the presentation request corresponding to the presentation cast + // mode, if supported. Otherwise set to nullopt. + absl::optional<content::PresentationRequest> presentation_request_; + + // Registered observers. + base::ObserverList<PresentationRequestSourceObserver>::Unchecked observers_; + + // NOTE: Weak pointers must be invalidated before all other member variables. + // Therefore |weak_factory_| must be placed at the end. + base::WeakPtrFactory<MediaRouteStarter> weak_factory_{this}; +}; + +} // namespace media_router + +#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_ROUTE_STARTER_H_
diff --git a/chrome/browser/ui/media_router/media_route_starter_unittest.cc b/chrome/browser/ui/media_router/media_route_starter_unittest.cc new file mode 100644 index 0000000..5a6239c2 --- /dev/null +++ b/chrome/browser/ui/media_router/media_route_starter_unittest.cc
@@ -0,0 +1,915 @@ +// Copyright 2022 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/media_router/media_route_starter.h" + +#include "base/json/json_reader.h" +#include "base/strings/strcat.h" +#include "chrome/browser/media/router/chrome_media_router_factory.h" +#include "chrome/browser/media/router/test/provider_test_helpers.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/sessions/session_tab_helper_factory.h" +#include "chrome/browser/ui/global_media_controls/test_helper.h" +#include "chrome/browser/ui/media_router/media_cast_mode.h" +#include "chrome/browser/ui/media_router/query_result_manager.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "components/media_router/browser/logger_impl.h" +#include "components/media_router/browser/media_router_factory.h" +#include "components/media_router/browser/media_sinks_observer.h" +#include "components/media_router/browser/presentation/web_contents_presentation_manager.h" +#include "components/media_router/browser/test/mock_media_router.h" +#include "components/media_router/browser/test/test_helper.h" +#include "components/media_router/common/discovery/media_sink_internal.h" +#include "components/media_router/common/media_sink.h" +#include "components/media_router/common/route_request_result.h" +#include "components/media_router/common/test/test_helper.h" +#include "components/sessions/content/session_tab_helper.h" +#include "content/public/browser/presentation_request.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" +#include "url/origin.h" + +#if BUILDFLAG(IS_MAC) +#include "base/mac/mac_util.h" +#include "ui/base/cocoa/permissions_utils.h" +#endif + +using testing::_; +using testing::Invoke; +using testing::NiceMock; +using testing::Return; + +namespace media_router { + +namespace { +constexpr char kPresentationId[] = "session-67890"; +constexpr char kLoggerComponent[] = "MediaRouteStarterTests"; + +const CastModeSet kAllModes = {MediaCastMode::PRESENTATION, + MediaCastMode::TAB_MIRROR, + MediaCastMode::DESKTOP_MIRROR}; +const CastModeSet kMirroringOnly = {MediaCastMode::TAB_MIRROR, + MediaCastMode::DESKTOP_MIRROR}; +const CastModeSet kPresentationOnly = {MediaCastMode::PRESENTATION}; +const CastModeSet kDestkopMirrorOnly = {MediaCastMode::DESKTOP_MIRROR}; + +constexpr char kDefaultPresentationUrl[] = "https://defaultpresentation.com/"; +constexpr char kDefaultOriginUrl[] = "https://default.fakeurl/"; + +constexpr char kStartPresentationUrl[] = "https://startpresentrequest.com/"; +constexpr char kStartOriginUrl[] = "https://start.fakeurl/"; + +class MockPresentationRequestSourceObserver + : public PresentationRequestSourceObserver { + public: + MockPresentationRequestSourceObserver() = default; + explicit MockPresentationRequestSourceObserver(MediaRouteStarter* starter) + : starter_(starter) { + starter_->AddPresentationRequestSourceObserver(this); + } + + ~MockPresentationRequestSourceObserver() override { + if (starter_) + starter_->RemovePresentationRequestSourceObserver(this); + } + + MOCK_METHOD(void, OnSourceUpdated, (std::u16string)); + + private: + raw_ptr<MediaRouteStarter> starter_ = nullptr; +}; + +// For demonstrating that presentation mode callbacks are made from the MRS +// d'tor +class PresentationRequestCallbacks { + public: + PresentationRequestCallbacks() = default; + + explicit PresentationRequestCallbacks( + const blink::mojom::PresentationError& expected_error) + : expected_error_(expected_error) {} + ~PresentationRequestCallbacks() { EXPECT_TRUE(called_); } + + void Success(const blink::mojom::PresentationInfo&, + mojom::RoutePresentationConnectionPtr, + const MediaRoute&) { + NOTREACHED(); + } + + void Error(const blink::mojom::PresentationError& error) { + EXPECT_EQ(expected_error_.error_type, error.error_type); + EXPECT_EQ(expected_error_.message, error.message); + called_ = true; + } + + private: + blink::mojom::PresentationError expected_error_; + bool called_ = false; +}; + +} // namespace + +class MediaRouteStarterTest : public ChromeRenderViewHostTestHarness { + public: + // For demonstrating that presentation mode casting callbacks are called. + MOCK_METHOD(void, + RequestSuccess, + (const blink::mojom::PresentationInfo&, + mojom::RoutePresentationConnectionPtr, + const MediaRoute&)); + MOCK_METHOD(void, + RequestError, + (const blink::mojom::PresentationError& error)); + + protected: + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + + presentation_manager_ = + std::make_unique<NiceMock<MockWebContentsPresentationManager>>(); + WebContentsPresentationManager::SetTestInstance(presentation_manager()); + + SetMediaRouterFactory(); + logger_ = std::make_unique<LoggerImpl>(); + + CreateSessionServiceTabHelper(web_contents()); + + cast_sink_ = CreateCastSink(1); + dial_sink_ = CreateDialSink(1); + + CreateStarter(kAllModes, web_contents(), nullptr); + } + + void TearDown() override { + clear_screen_capture_allowed_for_testing(); + DestroyMediaRouteStarter(); + profile_manager_->DeleteAllTestingProfiles(); + profile_manager_.reset(); + ChromeRenderViewHostTestHarness::TearDown(); + } + + virtual void SetMediaRouterFactory() { + ChromeMediaRouterFactory::GetInstance()->SetTestingFactory( + GetBrowserContext(), base::BindRepeating(&MockMediaRouter::Create)); + content::BrowserContext* original_profile = + Profile::FromBrowserContext(ProfileManager::GetActiveUserProfile()) + ->GetOriginalProfile(); + ChromeMediaRouterFactory::GetInstance()->SetTestingFactory( + original_profile, base::BindRepeating(&MockMediaRouter::Create)); + } + + void CreateStarter( + CastModeSet supported_modes, + content::WebContents* web_contents, + std::unique_ptr<StartPresentationContext> start_presentation_context) { + starter_ = std::make_unique<MediaRouteStarter>( + supported_modes, web_contents, std::move(start_presentation_context)); + starter_->SetLoggerComponent(kLoggerComponent); + ON_CALL(*media_router(), GetLogger()).WillByDefault(Return(logger_.get())); + // Store sink observers so that they can be notified in tests. + ON_CALL(*media_router(), RegisterMediaSinksObserver(_)) + .WillByDefault([this](MediaSinksObserver* observer) { + media_sinks_observers_.push_back(observer); + return true; + }); + // Remove sink observers as appropriate (destructing handlers will cause + // this to occur). + ON_CALL(*media_router(), UnregisterMediaSinksObserver(_)) + .WillByDefault([this](MediaSinksObserver* observer) { + auto it = std::find(media_sinks_observers_.begin(), + media_sinks_observers_.end(), observer); + if (it != media_sinks_observers_.end()) { + media_sinks_observers_.erase(it); + } + }); + // Handler so MockMediaRouter will respond to requests to create a route. + // Will construct a RouteRequestResult based on the set result code and + // then call the handler's callback. + ON_CALL(*media_router(), CreateRouteInternal(_, _, _, _, _, _, _)) + .WillByDefault([this](const MediaSource::Id& source_id, + const MediaSink::Id& sink_id, + const url::Origin& origin, + content::WebContents* web_contents, + MediaRouteResponseCallback& callback, + base::TimeDelta timeout, bool incognito) { + // This indicates the test did not properly set the expected result + EXPECT_NE(RouteRequestResult::ResultCode::UNKNOWN_ERROR, + result_code_); + std::unique_ptr<RouteRequestResult> result; + if (result_code_ == RouteRequestResult::ResultCode::OK) { + result = GetSuccessResult(source_id, sink_id); + } else { + result = GetErrorResult(result_code_); + } + std::move(callback).Run(nullptr, *result); + }); + } + + MediaRouteStarter* media_route_starter() { return starter_.get(); } + TestingProfileManager* profile_manager() { return profile_manager_.get(); } + MockMediaRouter* media_router() { + return static_cast<MockMediaRouter*>( + media_route_starter()->GetMediaRouter()); + } + LoggerImpl* logger() { return logger_.get(); } + + const std::vector<MediaSinksObserver*> media_sink_observers() { + return media_sinks_observers_; + } + + MockWebContentsPresentationManager* presentation_manager() { + return presentation_manager_.get(); + } + + QueryResultManager* query_result_manager() { + return media_route_starter()->GetQueryResultManager(); + } + + const RouteRequestResult* route_request_result() { + return route_request_result_.get(); + } + + const MediaSinkInternal& cast_sink() { return cast_sink_; } + const MediaSinkInternal& dial_sink() { return dial_sink_; } + + const content::PresentationRequest& default_presentation_request() { + return default_presentation_request_; + } + const content::PresentationRequest& start_presentation_request() { + return start_presentation_request_; + } + + void set_expected_cast_result(RouteRequestResult::ResultCode code) { + result_code_ = code; + } + + std::unique_ptr<StartPresentationContext> CreateStartPresentationContext( + const content::PresentationRequest& presentation_request, + StartPresentationContext::PresentationConnectionCallback success_cb = + base::DoNothing(), + StartPresentationContext::PresentationConnectionErrorCallback error_cb = + base::DoNothing()) { + return std::make_unique<StartPresentationContext>( + presentation_request, + base::BindOnce(&MediaRouteStarterTest::RequestSuccess, + base::Unretained(this)), + base::BindOnce(&MediaRouteStarterTest::RequestError, + base::Unretained(this))); + } + + // The caller must hold on to PresentationRequestCallbacks returned so that + // a callback can later be called on it. + std::unique_ptr<PresentationRequestCallbacks> ExpectPresentationError( + const content::PresentationRequest& presentation_request, + blink::mojom::PresentationErrorType error_type, + const std::string& error_message) { + blink::mojom::PresentationError expected_error(error_type, error_message); + auto request_callbacks = + std::make_unique<PresentationRequestCallbacks>(expected_error); + auto start_presentation_context = + std::make_unique<StartPresentationContext>( + presentation_request, + base::BindOnce(&PresentationRequestCallbacks::Success, + base::Unretained(request_callbacks.get())), + base::BindOnce(&PresentationRequestCallbacks::Error, + base::Unretained(request_callbacks.get()))); + CreateStarter(kPresentationOnly, web_contents(), + std::move(start_presentation_context)); + return request_callbacks; + } + + void UpdateSinks(const std::vector<MediaSink>& sinks, + const std::vector<url::Origin>& origins) { + for (MediaSinksObserver* sinks_observer : media_sink_observers()) { + sinks_observer->OnSinksUpdated(sinks, origins); + } + } + + std::string GetLogEntry(const std::string& logs_json, + const std::string& attribute) { + base::Value logs = base::JSONReader::Read(logs_json).value(); + return *logs.GetListDeprecated()[0].FindStringKey(attribute); + } + + void DestroyMediaRouteStarter() { starter_.reset(); } + + std::unique_ptr<RouteRequestResult> GetSuccessResult( + const MediaSource::Id& source_id, + const MediaSink::Id& sink_id) { + MediaSource source(source_id); + MediaRoute route; + route.set_media_route_id(source_id + "->" + sink_id); + route.set_media_source(source); + route.set_media_sink_id(sink_id); + return RouteRequestResult::FromSuccess( + route, IsValidPresentationUrl(source.url()) ? kPresentationId : ""); + } + + std::unique_ptr<RouteRequestResult> GetSuccessResult( + const content::PresentationRequest& request, + const MediaSink::Id& sink_id) { + auto source = + MediaSource::ForPresentationUrl(*(request.presentation_urls.begin())) + .id(); + return GetSuccessResult(source, sink_id); + } + + std::unique_ptr<RouteRequestResult> GetErrorResult( + RouteRequestResult::ResultCode result_code) { + return RouteRequestResult::FromError("unit test error", result_code); + } + + void StartMirroring(const MediaSinkInternal& sink, MediaCastMode cast_mode) { + EXPECT_NE(MediaCastMode::PRESENTATION, cast_mode); + + // Add a sink + UpdateSinks({sink.sink()}, std::vector<url::Origin>()); + + auto params = + media_route_starter()->CreateRouteParameters(sink.id(), cast_mode); + EXPECT_TRUE(params); + + if (cast_mode == MediaCastMode::DESKTOP_MIRROR) + set_screen_capture_allowed_for_testing(true); + + StartRoute(std::move(params)); + } + + void StartPresentation(const MediaSinkInternal& sink, + const content::PresentationRequest& request) { + // Add a presentation compatible sink + UpdateSinks({sink.sink()}, {request.frame_origin}); + + auto params = media_route_starter()->CreateRouteParameters( + sink.id(), MediaCastMode::PRESENTATION); + + EXPECT_TRUE(params); + + StartRoute(std::move(params)); + } + + private: + content::PresentationRequest CreatePresentationRequest( + const std::string& presentation_url, + const std::string& origin_url) { + content::PresentationRequest presentation_request( + {0, 0}, {GURL(presentation_url)}, + url::Origin::Create(GURL(origin_url))); + return presentation_request; + } + + void StartRoute(std::unique_ptr<RouteParameters> params) { + // To demonstrate that MediaRouteResultCallbacks are called + params->route_result_callbacks.emplace_back( + base::BindOnce(&MediaRouteStarterTest::HandleMediaRouteResponse, + base::Unretained(this))); + + EXPECT_CALL(*media_router(), + CreateRouteInternal(params->source_id, params->request->sink_id, + params->origin, web_contents(), _, + params->timeout, params->off_the_record)); + + media_route_starter()->StartRoute(std::move(params)); + } + + // For demonstrating that the MediaRouteResultCallbacks are called. + void HandleMediaRouteResponse(const RouteRequestResult& result) { + // Store the response so tests can examine it. + if (result.result_code() == RouteRequestResult::ResultCode::OK) { + auto route = std::make_unique<MediaRoute>(*result.route()); + route_request_result_ = std::make_unique<RouteRequestResult>( + std::move(route), result.presentation_id(), result.error(), + result.result_code()); + } else { + route_request_result_ = + RouteRequestResult::FromError(result.error(), result.result_code()); + } + } + + std::unique_ptr<MediaRouteStarter> starter_; + + std::unique_ptr<TestingProfileManager> profile_manager_; + + std::unique_ptr<LoggerImpl> logger_; + std::vector<MediaSinksObserver*> media_sinks_observers_; + + std::unique_ptr<MockWebContentsPresentationManager> presentation_manager_; + + MediaSinkInternal cast_sink_; + MediaSinkInternal dial_sink_; + + content::PresentationRequest default_presentation_request_ = + CreatePresentationRequest(kDefaultPresentationUrl, kDefaultOriginUrl); + content::PresentationRequest start_presentation_request_ = + CreatePresentationRequest(kStartPresentationUrl, kStartOriginUrl); + + RouteRequestResult::ResultCode result_code_ = + RouteRequestResult::ResultCode::UNKNOWN_ERROR; + std::unique_ptr<RouteRequestResult> route_request_result_; +}; + +// Demonstrates that when initialized with webcontents but no presentation +// source the supported modes are mirroring only. +TEST_F(MediaRouteStarterTest, Defaults_NoPresentation) { + CreateStarter(kAllModes, web_contents(), nullptr); + EXPECT_EQ(kMirroringOnly, query_result_manager()->GetSupportedCastModes()); +} + +// Demonstrates that when initialized with webcontents that has a default +// presentation that presentation mode is supported. +TEST_F(MediaRouteStarterTest, Defaults_WebContentPresentation) { + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + CreateStarter(kAllModes, web_contents(), nullptr); + EXPECT_EQ(kAllModes, query_result_manager()->GetSupportedCastModes()); +} + +// Demonstrates that if caller doesn't request mirroring that it is not +// available. +TEST_F(MediaRouteStarterTest, Defaults_WebContentPresentationOnly) { + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + CreateStarter(kPresentationOnly, web_contents(), nullptr); + EXPECT_EQ(kPresentationOnly, query_result_manager()->GetSupportedCastModes()); +} + +// Demonstrates that when initialized with a presentation request that +// presentation mode is supported - even if the web contents has no default +// presentation. +TEST_F(MediaRouteStarterTest, Defaults_StartPresentationContext) { + auto start_presentation_context = + CreateStartPresentationContext(start_presentation_request()); + + CreateStarter(kAllModes, web_contents(), + std::move(start_presentation_context)); + EXPECT_EQ(kAllModes, query_result_manager()->GetSupportedCastModes()); + + // This is to deal with the error callback in the d'tor that's not part of + // this test. See the Dtor_* tests below where this case is actually + // validated. + EXPECT_CALL(*this, RequestError(_)); +} + +// Demonstrates that when initialized with no webcontent or presentation source +// the supported modes are desktop mirroring only. +TEST_F(MediaRouteStarterTest, Defaults_NoWebContent) { + CreateStarter(kAllModes, nullptr, nullptr); + EXPECT_EQ(kDestkopMirrorOnly, + query_result_manager()->GetSupportedCastModes()); +} + +// Demonstrates that when MediaRouteStarter is notified that the presentation +// request source has changed, that it alerts observers with the name of that +// presentation request source. +TEST_F(MediaRouteStarterTest, OnPresentationRequestSourceUpdated) { + CreateStarter(kAllModes, web_contents(), nullptr); + EXPECT_EQ(kMirroringOnly, query_result_manager()->GetSupportedCastModes()); + + MockPresentationRequestSourceObserver observer(media_route_starter()); + + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + std::u16string expected_name(u"default.fakeurl"); + EXPECT_CALL(observer, OnSourceUpdated(expected_name)); + + // Simulate the notification that the default presentation has changed. + media_route_starter()->OnDefaultPresentationChanged( + &presentation_manager()->GetDefaultPresentationRequest()); + + // Now that a default presentation has been added the available modes should + // include presentation. + EXPECT_EQ(kAllModes, query_result_manager()->GetSupportedCastModes()); +} + +// Demonstrates that when MediaRouteStarter is notified that there is no +// presentation request source that it alerts observers that the name of the +// presentation source is empty. +TEST_F(MediaRouteStarterTest, OnPresentationRequestSourceRemoved) { + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + CreateStarter(kAllModes, web_contents(), nullptr); + EXPECT_EQ(kAllModes, query_result_manager()->GetSupportedCastModes()); + + MockPresentationRequestSourceObserver observer(media_route_starter()); + + // Simulate the notification that the default presentation has been removed. + std::u16string expected_name(u""); + EXPECT_CALL(observer, OnSourceUpdated(expected_name)); + + media_route_starter()->OnDefaultPresentationChanged(nullptr); + + // Now that a default presentation has been added the available modes should + // include presentation. + EXPECT_EQ(kMirroringOnly, query_result_manager()->GetSupportedCastModes()); +} + +// Demonstrates that if MediaRouteStarter is destroyed without an attempt to +// create a route with the presentation source, that the expected error is +// reported to the presentation source. +TEST_F(MediaRouteStarterTest, Dtor_NotFoundError_NoSinks) { + auto request_callbacks = ExpectPresentationError( + default_presentation_request(), + blink::mojom::PresentationErrorType::NO_AVAILABLE_SCREENS, + "No screens found."); + + // Destroying the starter should return the expected error from above to the + // error callback. + DestroyMediaRouteStarter(); +} + +// Same as above, but demonstrates the same error reporting even if sinks exist, +// so long as none of the sinks were compatible with the presentation source. +TEST_F(MediaRouteStarterTest, Dtor_NotFoundError_NoCompatibleSinks) { + auto request_callbacks = ExpectPresentationError( + default_presentation_request(), + blink::mojom::PresentationErrorType::NO_AVAILABLE_SCREENS, + "No screens found."); + // Send a sink to the UI that is compatible with sources other than the + // presentation url to cause a NotFoundError. + std::vector<MediaSink> sinks = {dial_sink().sink()}; + auto presentation_source = MediaSource::ForPresentationUrl( + default_presentation_request().presentation_urls[0]); + for (MediaSinksObserver* sinks_observer : media_sink_observers()) { + if (!(sinks_observer->source() == presentation_source)) { + sinks_observer->OnSinksUpdated(sinks, {}); + } + } + + // Destroying the starter should return the expected error from above to the + // error callback. + DestroyMediaRouteStarter(); +} + +// Same as above, but demonstrates that if a compatible sink was present, then +// the error that is reported indicates that the request was cancelled. +TEST_F(MediaRouteStarterTest, Dtor_AbortError) { + auto request_callbacks = ExpectPresentationError( + default_presentation_request(), + blink::mojom::PresentationErrorType::PRESENTATION_REQUEST_CANCELLED, + "Dialog closed."); + // Send a sink to the UI that is compatible with the presentation url to avoid + // a NotFoundError. + std::vector<MediaSink> sinks = {dial_sink().sink()}; + auto presentation_source = MediaSource::ForPresentationUrl( + default_presentation_request().presentation_urls[0]); + for (MediaSinksObserver* sinks_observer : media_sink_observers()) { + if (sinks_observer->source() == presentation_source) { + sinks_observer->OnSinksUpdated(sinks, {}); + } + } + + // Destroying the starter should return the expected error from above to the + // error callback. + DestroyMediaRouteStarter(); +} + +// Demonstrates that if there are no sources available for the desired mode +// CreateRouteParameters returns nothing. +TEST_F(MediaRouteStarterTest, CreateRouteParameters_NoValidSource) { + // No presentation available + CreateStarter(kMirroringOnly, web_contents(), nullptr); + + // Add a sink + UpdateSinks({cast_sink().sink()}, std::vector<url::Origin>()); + + auto params = media_route_starter()->CreateRouteParameters( + cast_sink().id(), MediaCastMode::PRESENTATION); + + EXPECT_FALSE(params); +} + +// Demonstrates that when desktop mirroring is available and requested that the +// RouteParameters are properly filled out. +TEST_F(MediaRouteStarterTest, CreateRouteParameters_DesktopMirroring) { + CreateStarter(kAllModes, web_contents(), nullptr); + + // Add a sink + UpdateSinks({cast_sink().sink()}, std::vector<url::Origin>()); + + auto params = media_route_starter()->CreateRouteParameters( + cast_sink().id(), MediaCastMode::DESKTOP_MIRROR); + + EXPECT_EQ(MediaCastMode::DESKTOP_MIRROR, params->cast_mode); + EXPECT_EQ(MediaSource::ForUnchosenDesktop().id(), params->source_id); + EXPECT_EQ(cast_sink().id(), params->request->sink_id); + EXPECT_EQ(GURL(), params->origin.GetURL()); + // route_result_callbacks should only be filled in by caller + EXPECT_EQ(0ul, params->route_result_callbacks.size()); + EXPECT_EQ(base::Seconds(120), params->timeout); + EXPECT_FALSE(params->off_the_record); +} + +// Demonstrates that when tab mirroring is available and requested that the +// RouteParameters are properly filled out. +TEST_F(MediaRouteStarterTest, CreateRouteParameters_TabMirroring) { + SessionID::id_type tab_id = + sessions::SessionTabHelper::IdForTab(web_contents()).id(); + + CreateStarter(kAllModes, web_contents(), nullptr); + + // Add a sink + UpdateSinks({cast_sink().sink()}, std::vector<url::Origin>()); + + auto params = media_route_starter()->CreateRouteParameters( + cast_sink().id(), MediaCastMode::TAB_MIRROR); + + EXPECT_EQ(MediaCastMode::TAB_MIRROR, params->cast_mode); + EXPECT_EQ(MediaSource::ForTab(tab_id).id(), params->source_id); + EXPECT_EQ(cast_sink().id(), params->request->sink_id); + EXPECT_EQ(GURL(), params->origin.GetURL()); + // route_result_callbacks should only be filled in by caller + EXPECT_EQ(0ul, params->route_result_callbacks.size()); + EXPECT_EQ(base::Seconds(60), params->timeout); + EXPECT_FALSE(params->off_the_record); +} + +// Demonstrates that when presentation mode is available for the default +// presentation and requested that the RouteParameters are properly filled out. +TEST_F(MediaRouteStarterTest, CreateRouteParameters_WebContentPresentation) { + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + CreateStarter(kAllModes, web_contents(), nullptr); + + // Add a presentation compatible sink + UpdateSinks({cast_sink().sink()}, + {default_presentation_request().frame_origin}); + + auto params = media_route_starter()->CreateRouteParameters( + cast_sink().id(), MediaCastMode::PRESENTATION); + + EXPECT_EQ(MediaCastMode::PRESENTATION, params->cast_mode); + EXPECT_EQ(MediaSource::ForPresentationUrl( + *(default_presentation_request()).presentation_urls.begin()) + .id(), + params->source_id); + EXPECT_EQ(cast_sink().id(), params->request->sink_id); + EXPECT_EQ(default_presentation_request().frame_origin, params->origin); + // route_result_callbacks should only be filled in by caller + EXPECT_EQ(0ul, params->route_result_callbacks.size()); + EXPECT_EQ(base::Seconds(20), params->timeout); + EXPECT_FALSE(params->off_the_record); +} + +// Demonstrates that when presentation mode is requested and a start +// presentation context is available that the RouteParameters are correctly +// filled out. +TEST_F(MediaRouteStarterTest, CreateRouteParameters_StartPresentationContext) { + auto start_presentation_context = + CreateStartPresentationContext(start_presentation_request()); + + CreateStarter(kAllModes, web_contents(), + std::move(start_presentation_context)); + + // Add a presentation compatible sink + UpdateSinks({cast_sink().sink()}, + {start_presentation_request().frame_origin}); + + auto params = media_route_starter()->CreateRouteParameters( + cast_sink().id(), MediaCastMode::PRESENTATION); + + EXPECT_EQ(MediaCastMode::PRESENTATION, params->cast_mode); + EXPECT_EQ(MediaSource::ForPresentationUrl( + *(start_presentation_request().presentation_urls.begin())) + .id(), + params->source_id); + EXPECT_EQ(cast_sink().id(), params->request->sink_id); + EXPECT_EQ(start_presentation_request().frame_origin, params->origin); + // route_result_callbacks should only be filled in by caller + EXPECT_EQ(0ul, params->route_result_callbacks.size()); + EXPECT_EQ(base::Seconds(20), params->timeout); + EXPECT_FALSE(params->off_the_record); + + // This is to deal with the error callback in the d'tor that's not part of + // this test. See the Dtor_* tests below where this case is actually + // validated. + EXPECT_CALL(*this, RequestError(_)); +} + +// Demonstrates that desktop mirroring routes are created correctly. +TEST_F(MediaRouteStarterTest, StartRoute_DesktopMirroring) { + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::OK); + + StartMirroring(cast_sink(), MediaCastMode::DESKTOP_MIRROR); + + EXPECT_EQ(RouteRequestResult::ResultCode::OK, + route_request_result()->result_code()); + + MediaSource expected_source = MediaSource::ForUnchosenDesktop(); + EXPECT_EQ(expected_source, route_request_result()->route()->media_source()); +} + +// Demonstrates that failures to create desktop mirroring routes are propagated. +TEST_F(MediaRouteStarterTest, StartRoute_DesktopMirroringError) { + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::ROUTE_NOT_FOUND); + + StartMirroring(cast_sink(), MediaCastMode::DESKTOP_MIRROR); + + EXPECT_EQ(RouteRequestResult::ResultCode::ROUTE_NOT_FOUND, + route_request_result()->result_code()); +} + +// Demonstrates that tab mirroring routes are created correctly. +TEST_F(MediaRouteStarterTest, StartRoute_TabMirroring) { + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::OK); + + StartMirroring(cast_sink(), MediaCastMode::TAB_MIRROR); + + EXPECT_EQ(RouteRequestResult::ResultCode::OK, + route_request_result()->result_code()); + + MediaSource expected_source = MediaSource::ForTab( + sessions::SessionTabHelper::IdForTab(web_contents()).id()); + EXPECT_EQ(expected_source, route_request_result()->route()->media_source()); +} + +// Demonstrates that failures to create tab mirroring routes are propagated. +TEST_F(MediaRouteStarterTest, StartRoute_TabMirroringError) { + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::INVALID_ORIGIN); + + StartMirroring(cast_sink(), MediaCastMode::DESKTOP_MIRROR); + + EXPECT_EQ(RouteRequestResult::ResultCode::INVALID_ORIGIN, + route_request_result()->result_code()); +} + +// Demonstrates that presentations routes from web content are created +// correctly. +TEST_F(MediaRouteStarterTest, StartRoute_WebContentPresentation) { + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::OK); + auto expected_result = + GetSuccessResult(default_presentation_request(), cast_sink().id()); + + EXPECT_CALL(*presentation_manager(), + OnPresentationResponse(default_presentation_request(), _, _)); + + StartPresentation(cast_sink(), default_presentation_request()); + + EXPECT_EQ(RouteRequestResult::ResultCode::OK, + route_request_result()->result_code()); + EXPECT_EQ(kDefaultPresentationUrl, + route_request_result()->presentation_url()); +} + +// Demonstrates that failures to create presentation routes from web content are +// propagated correctly. +TEST_F(MediaRouteStarterTest, StartRoute_WebContentPresentationError) { + presentation_manager()->SetDefaultPresentationRequest( + default_presentation_request()); + + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::INVALID_ORIGIN); + EXPECT_CALL(*presentation_manager(), + OnPresentationResponse(default_presentation_request(), _, _)); + + StartPresentation(cast_sink(), default_presentation_request()); + + EXPECT_EQ(RouteRequestResult::ResultCode::INVALID_ORIGIN, + route_request_result()->result_code()); +} + +// Demonstrates that presentations routes from start presentation contexts are +// created correctly. +TEST_F(MediaRouteStarterTest, StartRoute_StartPresentationContext) { + auto start_presentation_context = + CreateStartPresentationContext(start_presentation_request()); + + CreateStarter(kAllModes, web_contents(), + std::move(start_presentation_context)); + + set_expected_cast_result(RouteRequestResult::ResultCode::OK); + auto expected_result = + GetSuccessResult(start_presentation_request(), cast_sink().id()); + + EXPECT_CALL(*this, RequestSuccess(_, _, *expected_result->route())); + + StartPresentation(cast_sink(), start_presentation_request()); + + EXPECT_EQ(RouteRequestResult::ResultCode::OK, + route_request_result()->result_code()); + EXPECT_EQ(kStartPresentationUrl, route_request_result()->presentation_url()); +} + +// Demonstrates that failures to create presentation routes from start +// presentation contexts are created correctly. +TEST_F(MediaRouteStarterTest, StartRoute_StartPresentationContextError) { + auto start_presentation_context = + CreateStartPresentationContext(start_presentation_request()); + + CreateStarter(kAllModes, web_contents(), + std::move(start_presentation_context)); + + set_expected_cast_result( + RouteRequestResult::ResultCode::NO_SUPPORTED_PROVIDER); + + EXPECT_CALL(*this, RequestError(_)); + + StartPresentation(cast_sink(), start_presentation_request()); + + EXPECT_EQ(RouteRequestResult::ResultCode::NO_SUPPORTED_PROVIDER, + route_request_result()->result_code()); +} + +TEST_F(MediaRouteStarterTest, GetScreenCapturePermission) { + // Screen capturing can only be disallowed on MacOS above a certain version. +#if BUILDFLAG(IS_MAC) + bool screen_capture_is_allowed = !base::mac::IsAtLeastOS10_15(); +#else + bool screen_capture_is_allowed = true; +#endif // BUILDFLAG(IS_MAC) + set_screen_capture_allowed_for_testing(true); + // Always allowed for presentation mode and tab mirroring. + EXPECT_TRUE(MediaRouteStarter::GetScreenCapturePermission( + MediaCastMode::PRESENTATION)); + EXPECT_TRUE( + MediaRouteStarter::GetScreenCapturePermission(MediaCastMode::TAB_MIRROR)); + // Always allowed for desktop mode if permission has been granted + EXPECT_TRUE(MediaRouteStarter::GetScreenCapturePermission( + MediaCastMode::DESKTOP_MIRROR)); + + set_screen_capture_allowed_for_testing(false); + // Always allowed for presentation mode and tab mirroring. + EXPECT_TRUE(MediaRouteStarter::GetScreenCapturePermission( + MediaCastMode::PRESENTATION)); + EXPECT_TRUE( + MediaRouteStarter::GetScreenCapturePermission(MediaCastMode::TAB_MIRROR)); + // The question of whether permission needs to be granted depends on platform + // and version. + EXPECT_EQ(screen_capture_is_allowed, + MediaRouteStarter::GetScreenCapturePermission( + MediaCastMode::DESKTOP_MIRROR)); +} + +class MediaRouteStarterIncognitoTest : public MediaRouteStarterTest { + protected: + void SetMediaRouterFactory() override { + // We must set the factory on the non-incognito browser context. + MediaRouterFactory::GetInstance()->SetTestingFactory( + MediaRouteStarterTest::GetBrowserContext(), + base::BindRepeating(&MockMediaRouter::Create)); + } + + content::BrowserContext* GetBrowserContext() override { + return static_cast<Profile*>(MediaRouteStarterTest::GetBrowserContext()) + ->GetPrimaryOTRProfile(/*create_if_needed=*/true); + } +}; + +// Demonstrates that when tab mirroring is available and requested that the +// RouteParameters are properly filled out - particularly that the off the +// record is now true. +TEST_F(MediaRouteStarterIncognitoTest, CreateRouteParameters_TabMirroring) { + CreateStarter(kAllModes, web_contents(), nullptr); + + // Add a sink + UpdateSinks({cast_sink().sink()}, std::vector<url::Origin>()); + + auto params = media_route_starter()->CreateRouteParameters( + cast_sink().id(), MediaCastMode::TAB_MIRROR); + + EXPECT_TRUE(params->off_the_record); +} + +// Basically the same as the on the record case, but demonstrates that +// the incognito parameter is passed into MR. +TEST_F(MediaRouteStarterIncognitoTest, StartRoute_TabMirroring) { + CreateStarter(kAllModes, web_contents(), nullptr); + + set_expected_cast_result(RouteRequestResult::ResultCode::OK); + + StartMirroring(cast_sink(), MediaCastMode::TAB_MIRROR); + + EXPECT_EQ(RouteRequestResult::ResultCode::OK, + route_request_result()->result_code()); + + MediaSource expected_source = MediaSource::ForTab( + sessions::SessionTabHelper::IdForTab(web_contents()).id()); + EXPECT_EQ(expected_source, route_request_result()->route()->media_source()); +} + +} // namespace media_router
diff --git a/chrome/browser/ui/media_router/media_router_ui.cc b/chrome/browser/ui/media_router/media_router_ui.cc index 8eff3c13..64c7ac1 100644 --- a/chrome/browser/ui/media_router/media_router_ui.cc +++ b/chrome/browser/ui/media_router/media_router_ui.cc
@@ -689,7 +689,7 @@ UpdateSinks(); } -void MediaRouterUI::OnResultsUpdated( +void MediaRouterUI::OnSinksUpdated( const std::vector<MediaSinkWithCastModes>& sinks) { sinks_ = sinks;
diff --git a/chrome/browser/ui/media_router/media_router_ui.h b/chrome/browser/ui/media_router/media_router_ui.h index d9070aa..e298cd3 100644 --- a/chrome/browser/ui/media_router/media_router_ui.h +++ b/chrome/browser/ui/media_router/media_router_ui.h
@@ -21,6 +21,7 @@ #include "chrome/browser/ui/media_router/media_cast_mode.h" #include "chrome/browser/ui/media_router/media_router_ui_helper.h" #include "chrome/browser/ui/media_router/media_sink_with_cast_modes.h" +#include "chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h" #include "chrome/browser/ui/media_router/query_result_manager.h" #include "chrome/browser/ui/webui/media_router/web_contents_display_observer.h" #include "components/media_router/browser/issues_observer.h" @@ -53,7 +54,7 @@ // Functions as an intermediary between MediaRouter and Views Cast dialog. class MediaRouterUI : public CastDialogController, - public QueryResultManager::Observer, + public MediaSinkWithCastModesObserver, public WebContentsPresentationManager::Observer { public: struct RouteRequest { @@ -269,8 +270,8 @@ // Called by |routes_observer_| when the set of active routes has changed. void OnRoutesUpdated(const std::vector<MediaRoute>& routes); - // QueryResultManager::Observer: - void OnResultsUpdated( + // MediaSinkWithCastModesObserver: + void OnSinksUpdated( const std::vector<MediaSinkWithCastModes>& sinks) override; // Callback passed to MediaRouter to receive response to route creation
diff --git a/chrome/browser/ui/media_router/media_router_ui_helper.cc b/chrome/browser/ui/media_router/media_router_ui_helper.cc index 821ece2..263b7f9 100644 --- a/chrome/browser/ui/media_router/media_router_ui_helper.cc +++ b/chrome/browser/ui/media_router/media_router_ui_helper.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/media_router/media_router_ui_helper.h" +#include "base/atomic_sequence_num.h" #include "base/time/time.h" #include "build/build_config.h" #include "extensions/browser/extension_registry.h" @@ -95,6 +96,13 @@ #endif } +RouteRequest::RouteRequest(const MediaSink::Id& sink_id) : sink_id(sink_id) { + static base::AtomicSequenceNumber g_next_request_id; + id = g_next_request_id.GetNext(); +} + +RouteRequest::~RouteRequest() = default; + RouteParameters::RouteParameters() = default; RouteParameters::RouteParameters(RouteParameters&& other) = default;
diff --git a/chrome/browser/ui/media_router/media_router_ui_helper.h b/chrome/browser/ui/media_router/media_router_ui_helper.h index e04f2a6..094a8bf 100644 --- a/chrome/browser/ui/media_router/media_router_ui_helper.h +++ b/chrome/browser/ui/media_router/media_router_ui_helper.h
@@ -12,6 +12,7 @@ #include "build/build_config.h" #include "chrome/browser/ui/media_router/media_cast_mode.h" #include "components/media_router/browser/media_router.h" +#include "components/media_router/common/media_sink.h" #include "components/media_router/common/media_source.h" #include "url/origin.h" @@ -48,6 +49,15 @@ using MediaRouteResultCallback = base::OnceCallback<void(const RouteRequestResult&)>; +struct RouteRequest { + public: + explicit RouteRequest(const MediaSink::Id& sink_id); + ~RouteRequest(); + + int id; + MediaSink::Id sink_id; +}; + // Contains common parameters for route requests to MediaRouter. struct RouteParameters { public: @@ -57,15 +67,21 @@ RouteParameters& operator=(RouteParameters&& other); + MediaCastMode cast_mode; + // A string identifying the media source, which should be the source for this // route (e.g. a presentation url, tab mirroring id, etc.). MediaSource::Id source_id; + // Unique id identifying the attempt to connect to a specific sink + std::unique_ptr<RouteRequest> request; + // The origin of the page requesting the route. url::Origin origin; // This callback will be null if the route request is not for a presentation // (e.g. it is for tab mirroring). + // TODO(b/213324920): Remove this field after MRS refactor is complete. MediaRouteResponseCallback presentation_callback; // Callbacks which should be invoked on both success and failure of the route
diff --git a/chrome/browser/ui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/media_router/media_router_ui_unittest.cc index db9ff57..7018a4a 100644 --- a/chrome/browser/ui/media_router/media_router_ui_unittest.cc +++ b/chrome/browser/ui/media_router/media_router_ui_unittest.cc
@@ -178,9 +178,9 @@ // These methods are used so that we don't have to friend each test case that // calls the private methods. - void NotifyUiOnResultsUpdated( + void NotifyUiOnSinksUpdated( const std::vector<MediaSinkWithCastModes>& sinks) { - ui_->OnResultsUpdated(sinks); + ui_->OnSinksUpdated(sinks); } void NotifyUiOnRoutesUpdated(const std::vector<MediaRoute>& routes) { ui_->OnRoutesUpdated(routes); @@ -204,7 +204,7 @@ int timeout_seconds) { NiceMock<MockControllerObserver> observer(ui_.get()); MediaSink sink{CreateCastSink(kSinkId, kSinkName)}; - ui_->OnResultsUpdated({{sink, {cast_mode}}}); + ui_->OnSinksUpdated({{sink, {cast_mode}}}); MediaRouteResponseCallback callback; EXPECT_CALL(*mock_router_, CreateRouteInternal(_, _, _, _, _, @@ -281,7 +281,7 @@ base::Contains(ui_sink.cast_modes, MediaCastMode::TAB_MIRROR)); EXPECT_EQ(sink.icon_type(), ui_sink.icon_type); }))); - NotifyUiOnResultsUpdated({sink_with_cast_modes}); + NotifyUiOnSinksUpdated({sink_with_cast_modes}); MediaRoute route(kRouteId, MediaSource(kSourceId), kSinkId, "", true); EXPECT_CALL(observer, OnModelUpdated(_)) @@ -312,7 +312,7 @@ sink.description().value()), model.media_sinks()[0].friendly_name); })); - NotifyUiOnResultsUpdated({sink_with_cast_modes}); + NotifyUiOnSinksUpdated({sink_with_cast_modes}); } TEST_F(MediaRouterViewsUITest, SetDialogHeader) { @@ -443,8 +443,8 @@ TEST_F(MediaRouterViewsUITest, AddAndRemoveIssue) { MediaSink sink1{CreateCastSink("sink_id1", "Sink 1")}; MediaSink sink2{CreateCastSink("sink_id2", "Sink 2")}; - NotifyUiOnResultsUpdated({{sink1, {MediaCastMode::TAB_MIRROR}}, - {sink2, {MediaCastMode::TAB_MIRROR}}}); + NotifyUiOnSinksUpdated({{sink1, {MediaCastMode::TAB_MIRROR}}, + {sink2, {MediaCastMode::TAB_MIRROR}}}); NiceMock<MockControllerObserver> observer(ui_.get()); NiceMock<MockIssuesObserver> issues_observer(mock_router_->GetIssueManager()); @@ -521,7 +521,7 @@ set_screen_capture_allowed_for_testing(false); MockControllerObserver observer(ui_.get()); MediaSink sink{CreateCastSink(kSinkId, kSinkName)}; - ui_->OnResultsUpdated({{sink, {MediaCastMode::DESKTOP_MIRROR}}}); + ui_->OnSinksUpdated({{sink, {MediaCastMode::DESKTOP_MIRROR}}}); for (MediaSinksObserver* sinks_observer : media_sinks_observers_) sinks_observer->OnSinksUpdated({sink}, std::vector<url::Origin>()); @@ -537,9 +537,9 @@ #endif TEST_F(MediaRouterViewsUITest, SortedSinks) { - NotifyUiOnResultsUpdated({{CreateCastSink("sink3", "B sink"), {}}, - {CreateCastSink("sink2", "A sink"), {}}, - {CreateCastSink("sink1", "B sink"), {}}}); + NotifyUiOnSinksUpdated({{CreateCastSink("sink3", "B sink"), {}}, + {CreateCastSink("sink2", "A sink"), {}}, + {CreateCastSink("sink1", "B sink"), {}}}); // Sort first by name, then by ID. const auto& sorted_sinks = ui_->GetEnabledSinks(); @@ -549,7 +549,7 @@ } TEST_F(MediaRouterViewsUITest, SortSinksByIconType) { - NotifyUiOnResultsUpdated( + NotifyUiOnSinksUpdated( {{MediaSink{"id1", "B sink", SinkIconType::CAST_AUDIO_GROUP, mojom::MediaRouteProviderId::CAST}, {}}, @@ -641,7 +641,7 @@ display_observer_unique.get(); ui_->display_observer_ = std::move(display_observer_unique); - NotifyUiOnResultsUpdated( + NotifyUiOnSinksUpdated( {{CreateWiredDisplaySink(display_sink_id1, "sink"), {}}, {CreateWiredDisplaySink(display_sink_id2, "sink"), {}}, {CreateDialSink("id3", "sink"), {}}});
diff --git a/chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h b/chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h new file mode 100644 index 0000000..5d5490f1 --- /dev/null +++ b/chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h
@@ -0,0 +1,27 @@ +// Copyright 2022 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_UI_MEDIA_ROUTER_MEDIA_SINK_WITH_CAST_MODES_OBSERVER_H_ +#define CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_SINK_WITH_CAST_MODES_OBSERVER_H_ + +#include <vector> + +#include "chrome/browser/ui/media_router/media_sink_with_cast_modes.h" + +namespace media_router { + +// This interface can be used for observing updates about what |MediaSink| and +// |MediaCastMode| combinations can be cast to. Classes such as +// |QueryResultManager| or |MediaStartRouter| will alert on these changes. +class MediaSinkWithCastModesObserver { + public: + virtual ~MediaSinkWithCastModesObserver() = default; + + virtual void OnSinksUpdated( + const std::vector<MediaSinkWithCastModes>& sinks) = 0; +}; + +} // namespace media_router + +#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_MEDIA_SINK_WITH_CAST_MODES_OBSERVER_H_
diff --git a/chrome/browser/ui/media_router/presentation_request_source_observer.h b/chrome/browser/ui/media_router/presentation_request_source_observer.h new file mode 100644 index 0000000..bf1788d --- /dev/null +++ b/chrome/browser/ui/media_router/presentation_request_source_observer.h
@@ -0,0 +1,21 @@ +// Copyright 2022 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_UI_MEDIA_ROUTER_PRESENTATION_REQUEST_SOURCE_OBSERVER_H_ +#define CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_REQUEST_SOURCE_OBSERVER_H_ + +namespace media_router { + +// This interface is used for observing updates from |MediaRouteStarter| when +// the presentation source for casting changes. +class PresentationRequestSourceObserver { + public: + virtual ~PresentationRequestSourceObserver() = default; + + virtual void OnSourceUpdated(std::u16string source_name) = 0; +}; + +} // namespace media_router + +#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_REQUEST_SOURCE_OBSERVER_H_
diff --git a/chrome/browser/ui/media_router/query_result_manager.cc b/chrome/browser/ui/media_router/query_result_manager.cc index 71c4ac38..c569ccb 100644 --- a/chrome/browser/ui/media_router/query_result_manager.cc +++ b/chrome/browser/ui/media_router/query_result_manager.cc
@@ -90,13 +90,14 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -void QueryResultManager::AddObserver(Observer* observer) { +void QueryResultManager::AddObserver(MediaSinkWithCastModesObserver* observer) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(observer); observers_.AddObserver(observer); } -void QueryResultManager::RemoveObserver(Observer* observer) { +void QueryResultManager::RemoveObserver( + MediaSinkWithCastModesObserver* observer) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(observer); observers_.RemoveObserver(observer); @@ -277,8 +278,8 @@ void QueryResultManager::NotifyOnResultsUpdated() { std::vector<MediaSinkWithCastModes> sinks = GetSinksWithCastModes(); - for (QueryResultManager::Observer& observer : observers_) - observer.OnResultsUpdated(sinks); + for (MediaSinkWithCastModesObserver& observer : observers_) + observer.OnSinksUpdated(sinks); } } // namespace media_router
diff --git a/chrome/browser/ui/media_router/query_result_manager.h b/chrome/browser/ui/media_router/query_result_manager.h index af4eba97..1c6c0c1 100644 --- a/chrome/browser/ui/media_router/query_result_manager.h +++ b/chrome/browser/ui/media_router/query_result_manager.h
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/media_router/cast_modes_with_media_sources.h" #include "chrome/browser/ui/media_router/media_cast_mode.h" #include "chrome/browser/ui/media_router/media_sink_with_cast_modes.h" +#include "chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h" #include "components/media_router/browser/media_routes_observer.h" #include "components/media_router/common/media_sink.h" #include "components/media_router/common/media_source.h" @@ -39,7 +40,7 @@ // Typical use: // // url::Origin origin{GURL("https://origin.com")}; -// QueryResultManager::Observer* observer = ...; +// MediaSinkWithCastModesObserver* observer = ...; // QueryResultManager result_manager(router); // result_manager.AddObserver(observer); // result_manager.SetSourcesForCastMode(MediaCastMode::PRESENTATION, @@ -47,7 +48,7 @@ // result_manager.SetSourcesForCastMode(MediaCastMode::TAB_MIRROR, // {MediaSourceForTab(123)}, origin); // ... -// [Updates will be received by observer via OnResultsUpdated()] +// [Updates will be received by observer via OnSinksUpdated()] // ... // [When info on MediaSource is needed, i.e. when requesting route for a mode] // CastModeSet cast_modes = result_manager.GetSupportedCastModes(); @@ -62,16 +63,6 @@ // Not thread-safe. Must be used on the UI thread. class QueryResultManager { public: - class Observer { - public: - virtual ~Observer() {} - - // Updated results have been received. - // |sinks|: List of sinks and the cast modes they are compatible with. - virtual void OnResultsUpdated( - const std::vector<MediaSinkWithCastModes>& sinks) = 0; - }; - explicit QueryResultManager(MediaRouter* media_router); QueryResultManager(const QueryResultManager&) = delete; @@ -80,8 +71,8 @@ ~QueryResultManager(); // Adds/removes an observer that is notified with query results. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); + void AddObserver(MediaSinkWithCastModesObserver* observer); + void RemoveObserver(MediaSinkWithCastModesObserver* observer); // Requests a list of MediaSinks compatible with |sources| for |cast_mode| // from |origin|. |sources| should be in descending order of priority. @@ -190,7 +181,7 @@ std::vector<MediaSink> all_sinks_; // Registered observers. - base::ObserverList<Observer>::Unchecked observers_; + base::ObserverList<MediaSinkWithCastModesObserver>::Unchecked observers_; // Not owned by this object. const raw_ptr<MediaRouter> router_;
diff --git a/chrome/browser/ui/media_router/query_result_manager_unittest.cc b/chrome/browser/ui/media_router/query_result_manager_unittest.cc index 0264e5c0..a8b7c71 100644 --- a/chrome/browser/ui/media_router/query_result_manager_unittest.cc +++ b/chrome/browser/ui/media_router/query_result_manager_unittest.cc
@@ -31,9 +31,9 @@ const char kOrigin[] = "https://origin.com"; -class MockObserver : public QueryResultManager::Observer { +class MockObserver : public MediaSinkWithCastModesObserver { public: - MOCK_METHOD1(OnResultsUpdated, + MOCK_METHOD1(OnSinksUpdated, void(const std::vector<MediaSinkWithCastModes>& sinks)); }; @@ -50,7 +50,7 @@ void DiscoverSinks(MediaCastMode cast_mode, const MediaSource& source) { EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)) .WillOnce(Return(true)); - EXPECT_CALL(mock_observer_, OnResultsUpdated(_)); + EXPECT_CALL(mock_observer_, OnSinksUpdated(_)); query_result_manager_.SetSourcesForCastMode( cast_mode, {source}, url::Origin::Create(GURL(kOrigin))); } @@ -97,12 +97,12 @@ query_result_manager_.AddObserver(&ob1); query_result_manager_.AddObserver(&ob2); - EXPECT_CALL(ob1, OnResultsUpdated(_)); - EXPECT_CALL(ob2, OnResultsUpdated(_)); + EXPECT_CALL(ob1, OnSinksUpdated(_)); + EXPECT_CALL(ob2, OnSinksUpdated(_)); query_result_manager_.NotifyOnResultsUpdated(); query_result_manager_.RemoveObserver(&ob2); - EXPECT_CALL(ob1, OnResultsUpdated(_)); + EXPECT_CALL(ob1, OnSinksUpdated(_)); query_result_manager_.NotifyOnResultsUpdated(); query_result_manager_.RemoveObserver(&ob1); @@ -181,8 +181,7 @@ const auto& sinks_observers = query_result_manager_.sinks_observers_; auto* any_sink_observer = sinks_observers.find(absl::optional<MediaSource>())->second.get(); - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); any_sink_observer->OnSinksUpdated(sinks_query_result, {}); // Action: PRESENTATION -> [1, 2, 3]. @@ -193,8 +192,7 @@ {sink4, {}}}; auto* presentation1_sinks_observer = sinks_observers.find(presentation_source1)->second.get(); - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); presentation1_sinks_observer->OnSinksUpdated(sinks_query_result, {}); // Action: TAB_MIRROR -> [2, 3, 4]. @@ -205,8 +203,7 @@ {sink3, {MediaCastMode::PRESENTATION, MediaCastMode::TAB_MIRROR}}, {sink4, {MediaCastMode::TAB_MIRROR}}}; auto* tab_sinks_observer = sinks_observers.find(tab_source)->second.get(); - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); tab_sinks_observer->OnSinksUpdated(sinks_query_result, {url::Origin::Create(GURL(kOrigin))}); @@ -220,8 +217,7 @@ // The observer for the new source will be registered. EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)) .WillOnce(Return(true)); - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); query_result_manager_.SetSourcesForCastMode( MediaCastMode::PRESENTATION, {presentation_source2}, url::Origin::Create(GURL(kOrigin))); @@ -231,8 +227,7 @@ sinks_query_result = {sink1}; auto* presentation2_sinks_observer = sinks_observers.find(presentation_source2)->second.get(); - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); presentation2_sinks_observer->OnSinksUpdated( sinks_query_result, {url::Origin::Create(GURL("https://differentOrigin.com"))}); @@ -243,15 +238,13 @@ expected_sinks = {{sink2, {MediaCastMode::TAB_MIRROR}}, {sink3, {MediaCastMode::TAB_MIRROR}}, {sink4, {MediaCastMode::TAB_MIRROR}}}; - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); any_sink_observer->OnSinksUpdated(sinks_query_result, {}); // Action: Remove TAB_MIRROR observer. // |sink4| gets removed because none of the sink observers see it. expected_sinks = {{sink2, {}}, {sink3, {}}}; - EXPECT_CALL(mock_observer_, - OnResultsUpdated(VectorSetEquals(expected_sinks))); + EXPECT_CALL(mock_observer_, OnSinksUpdated(VectorSetEquals(expected_sinks))); EXPECT_CALL(mock_router_, UnregisterMediaSinksObserver(_)); query_result_manager_.RemoveSourcesForCastMode(MediaCastMode::TAB_MIRROR);
diff --git a/chrome/browser/ui/quick_answers/BUILD.gn b/chrome/browser/ui/quick_answers/BUILD.gn index 147d5e8d..c1974ae 100644 --- a/chrome/browser/ui/quick_answers/BUILD.gn +++ b/chrome/browser/ui/quick_answers/BUILD.gn
@@ -44,4 +44,11 @@ "//chrome/browser/ui/color:color_headers", ] } + + if (is_chromeos_lacros) { + sources += [ + "lacros/quick_answers_state_lacros.cc", + "lacros/quick_answers_state_lacros.h", + ] + } }
diff --git a/chrome/browser/ui/quick_answers/lacros/quick_answers_state_lacros.cc b/chrome/browser/ui/quick_answers/lacros/quick_answers_state_lacros.cc new file mode 100644 index 0000000..c890bd3 --- /dev/null +++ b/chrome/browser/ui/quick_answers/lacros/quick_answers_state_lacros.cc
@@ -0,0 +1,143 @@ +// Copyright 2021 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/quick_answers/lacros/quick_answers_state_lacros.h" + +#include "base/callback.h" +#include "base/logging.h" +#include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h" +#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h" +#include "chromeos/lacros/lacros_service.h" +#include "components/prefs/pref_service.h" + +namespace { + +void SetPref(crosapi::mojom::PrefPath path, base::Value value) { + auto* lacros_service = chromeos::LacrosService::Get(); + if (!lacros_service || + !lacros_service->IsAvailable<crosapi::mojom::Prefs>()) { + LOG(WARNING) << "crosapi: Prefs API not available"; + return; + } + lacros_service->GetRemote<crosapi::mojom::Prefs>()->SetPref( + path, std::move(value), base::DoNothing()); +} + +} // namespace + +QuickAnswersStateLacros::QuickAnswersStateLacros() { + settings_enabled_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kQuickAnswersEnabled, + base::BindRepeating(&QuickAnswersStateLacros::OnSettingsEnabledChanged, + base::Unretained(this))); + consent_status_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kQuickAnswersConsentStatus, + base::BindRepeating(&QuickAnswersStateLacros::OnConsentStatusChanged, + base::Unretained(this))); + definition_enabled_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kQuickAnswersDefinitionEnabled, + base::BindRepeating(&QuickAnswersStateLacros::OnDefinitionEnabledChanged, + base::Unretained(this))); + translation_enabled_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kQuickAnswersTranslationEnabled, + base::BindRepeating(&QuickAnswersStateLacros::OnTranslationEnabledChanged, + base::Unretained(this))); + unit_conversion_enabled_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kQuickAnswersUnitConversionEnabled, + base::BindRepeating( + &QuickAnswersStateLacros::OnUnitConversionEnabledChanged, + base::Unretained(this))); + application_locale_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kApplicationLocale, + base::BindRepeating(&QuickAnswersStateLacros::OnApplicationLocaleChanged, + base::Unretained(this))); + preferred_languages_observer_ = std::make_unique<CrosapiPrefObserver>( + crosapi::mojom::PrefPath::kPreferredLanguages, + base::BindRepeating(&QuickAnswersStateLacros::OnPreferredLanguagesChanged, + base::Unretained(this))); +} + +QuickAnswersStateLacros::~QuickAnswersStateLacros() = default; + +void QuickAnswersStateLacros::OnSettingsEnabledChanged(base::Value value) { + DCHECK(value.is_bool()); + bool settings_enabled = value.GetBool(); + + if (settings_enabled_ == settings_enabled) { + return; + } + settings_enabled_ = settings_enabled; + + // If the user turn on the Quick Answers in settings, set the consented status + // to true. + if (settings_enabled_) { + SetPref(crosapi::mojom::PrefPath::kQuickAnswersConsentStatus, + base::Value(quick_answers::prefs::ConsentStatus::kAccepted)); + } + + for (auto& observer : observers_) + observer.OnSettingsEnabled(settings_enabled_); +} + +void QuickAnswersStateLacros::OnConsentStatusChanged(base::Value value) { + DCHECK(value.is_int()); + + auto consent_status = + static_cast<quick_answers::prefs::ConsentStatus>(value.GetInt()); + if (consent_status_ == consent_status) { + return; + } + consent_status_ = consent_status; +} + +void QuickAnswersStateLacros::OnDefinitionEnabledChanged(base::Value value) { + DCHECK(value.is_bool()); + bool definition_enabled = value.GetBool(); + + if (definition_enabled_ == definition_enabled) { + return; + } + definition_enabled_ = definition_enabled; +} + +void QuickAnswersStateLacros::OnTranslationEnabledChanged(base::Value value) { + DCHECK(value.is_bool()); + bool translation_enabled = value.GetBool(); + + if (translation_enabled_ == translation_enabled) { + return; + } + translation_enabled_ = translation_enabled; +} + +void QuickAnswersStateLacros::OnUnitConversionEnabledChanged( + base::Value value) { + DCHECK(value.is_bool()); + bool unit_conversion_enabled = value.GetBool(); + + if (unit_conversion_enabled_ == unit_conversion_enabled) { + return; + } + unit_conversion_enabled_ = unit_conversion_enabled; +} + +void QuickAnswersStateLacros::OnApplicationLocaleChanged(base::Value value) { + DCHECK(value.is_string()); + auto application_locale = value.GetString(); + + if (application_locale_ == application_locale) { + return; + } + application_locale_ = application_locale; +} + +void QuickAnswersStateLacros::OnPreferredLanguagesChanged(base::Value value) { + DCHECK(value.is_string()); + auto preferred_languages = value.GetString(); + + if (preferred_languages_ == preferred_languages) { + return; + } + preferred_languages_ = preferred_languages; +}
diff --git a/chrome/browser/ui/quick_answers/lacros/quick_answers_state_lacros.h b/chrome/browser/ui/quick_answers/lacros/quick_answers_state_lacros.h new file mode 100644 index 0000000..3c51a49 --- /dev/null +++ b/chrome/browser/ui/quick_answers/lacros/quick_answers_state_lacros.h
@@ -0,0 +1,40 @@ +// Copyright 2021 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_UI_QUICK_ANSWERS_LACROS_QUICK_ANSWERS_STATE_LACROS_H_ +#define CHROME_BROWSER_UI_QUICK_ANSWERS_LACROS_QUICK_ANSWERS_STATE_LACROS_H_ + +#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h" +#include "chromeos/lacros/crosapi_pref_observer.h" +#include "components/prefs/pref_service.h" + +// A class that holds Quick Answers related prefs and states in Lacros browser. +class QuickAnswersStateLacros : public QuickAnswersState { + public: + QuickAnswersStateLacros(); + + QuickAnswersStateLacros(const QuickAnswersStateLacros&) = delete; + QuickAnswersStateLacros& operator=(const QuickAnswersStateLacros&) = delete; + + ~QuickAnswersStateLacros(); + + private: + void OnSettingsEnabledChanged(base::Value value); + void OnConsentStatusChanged(base::Value value); + void OnDefinitionEnabledChanged(base::Value value); + void OnTranslationEnabledChanged(base::Value value); + void OnUnitConversionEnabledChanged(base::Value value); + void OnApplicationLocaleChanged(base::Value value); + void OnPreferredLanguagesChanged(base::Value value); + + std::unique_ptr<CrosapiPrefObserver> settings_enabled_observer_; + std::unique_ptr<CrosapiPrefObserver> consent_status_observer_; + std::unique_ptr<CrosapiPrefObserver> definition_enabled_observer_; + std::unique_ptr<CrosapiPrefObserver> translation_enabled_observer_; + std::unique_ptr<CrosapiPrefObserver> unit_conversion_enabled_observer_; + std::unique_ptr<CrosapiPrefObserver> application_locale_observer_; + std::unique_ptr<CrosapiPrefObserver> preferred_languages_observer_; +}; + +#endif // CHROME_BROWSER_UI_QUICK_ANSWERS_LACROS_QUICK_ANSWERS_STATE_LACROS_H_
diff --git a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc index 6db5490..052e50f 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc +++ b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc
@@ -60,6 +60,11 @@ return popup_showing_; } +bool TestToolbarActionViewController::IsRequestingSiteAccess( + content::WebContents* web_contents) const { + return false; +} + void TestToolbarActionViewController::HidePopup() { popup_showing_ = false; delegate_->OnPopupClosed();
diff --git a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h index c20262b..89665c8 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h +++ b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h
@@ -33,6 +33,8 @@ std::u16string GetTooltip(content::WebContents* web_contents) const override; bool IsEnabled(content::WebContents* web_contents) const override; bool IsShowingPopup() const override; + bool IsRequestingSiteAccess( + content::WebContents* web_contents) const override; void HidePopup() override; gfx::NativeView GetPopupNativeView() override; ui::MenuModel* GetContextMenu(
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h index 03b7aec..c8eb499 100644 --- a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h +++ b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
@@ -89,6 +89,10 @@ // Returns whether there is currently a popup visible. virtual bool IsShowingPopup() const = 0; + // Returns whether the action is requesting site access to `web_contents`. + virtual bool IsRequestingSiteAccess( + content::WebContents* web_contents) const = 0; + // Hides the current popup, if one is visible. virtual void HidePopup() = 0;
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc index bffa021d..8683471d 100644 --- a/chrome/browser/ui/views/accelerator_table.cc +++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -65,10 +65,13 @@ #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) {ui::VKEY_9, ui::EF_ALT_DOWN, IDC_SELECT_LAST_TAB}, {ui::VKEY_NUMPAD9, ui::EF_ALT_DOWN, IDC_SELECT_LAST_TAB}, +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) {ui::VKEY_NEXT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, IDC_MOVE_TAB_NEXT}, {ui::VKEY_PRIOR, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, IDC_MOVE_TAB_PREVIOUS}, -#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || + // BUILDFLAG(IS_WIN) // Control modifier is rarely used on Mac, so we allow it only in several // specific cases. {ui::VKEY_TAB, ui::EF_CONTROL_DOWN, IDC_SELECT_NEXT_TAB},
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_button.cc b/chrome/browser/ui/views/extensions/extensions_request_access_button.cc index b2ca86f..3c0ec3c 100644 --- a/chrome/browser/ui/views/extensions/extensions_request_access_button.cc +++ b/chrome/browser/ui/views/extensions/extensions_request_access_button.cc
@@ -6,23 +6,30 @@ #include <memory> #include "base/bind.h" +#include "base/check_op.h" #include "chrome/grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" ExtensionsRequestAccessButton::ExtensionsRequestAccessButton() : ToolbarButton( base::BindRepeating(&ExtensionsRequestAccessButton::OnButtonPressed, - base::Unretained(this))) { + base::Unretained(this))) {} + +ExtensionsRequestAccessButton::~ExtensionsRequestAccessButton() = default; + +void ExtensionsRequestAccessButton::UpdateLabel( + int extensions_requesting_access_count) { + DCHECK_GT(extensions_requesting_access_count, 0); // TODO(crbug.com/1239772): Set the label and background color without borders // separately to match the mocks. For now, using SetHighlight to display that // adds a border and highlight color in addition to the label. absl::optional<SkColor> color; - SetHighlight(l10n_util::GetStringUTF16(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON), - color); + SetHighlight( + l10n_util::GetStringFUTF16Int(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON, + extensions_requesting_access_count), + color); } -ExtensionsRequestAccessButton::~ExtensionsRequestAccessButton() = default; - // TODO(crbug.com/1239772): Grant access to all the extensions requesting access // when the button is pressed. void ExtensionsRequestAccessButton::OnButtonPressed() {}
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_button.h b/chrome/browser/ui/views/extensions/extensions_request_access_button.h index 3785c3a..b3e79f42 100644 --- a/chrome/browser/ui/views/extensions/extensions_request_access_button.h +++ b/chrome/browser/ui/views/extensions/extensions_request_access_button.h
@@ -17,6 +17,10 @@ const ExtensionsRequestAccessButton&) = delete; ~ExtensionsRequestAccessButton() override; + // Updates the label based on the `extensions_requesting_access_count`. This + // should only be called if there is at least one extension requesting access. + void UpdateLabel(int extensions_requesting_access_count); + private: void OnButtonPressed(); };
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc index f77236a..4d4e2f89 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -848,14 +848,22 @@ if (!extensions_controls_) return; + content::WebContents* web_contents = GetCurrentWebContents(); + extensions_controls_->UpdateSiteAccessButtonVisibility( ExtensionActionViewController::AnyActionHasCurrentSiteAccess( - actions_, GetCurrentWebContents())); + actions_, web_contents)); - // TODO(crbug.com/1239772): Get extensions that are requesting access to the - // current site. - const std::vector<std::unique_ptr<ToolbarActionViewController>> actions; - extensions_controls_->UpdateRequestAccessButton(actions); + // TODO(crbug.com/1239772): The request access button should only include + // extensions that are requesting access to a restricted site. + // `SiteInteraction::kPending` includes extensions with activeTab, that can + // request access to restricted or non-restricted sites. Need to update the + // method to not take into account activeTab extensions. + int count_requesting_extensions = std::count_if( + actions_.begin(), actions_.end(), [web_contents](const auto& action) { + return action->IsRequestingSiteAccess(web_contents); + }); + extensions_controls_->UpdateRequestAccessButton(count_requesting_extensions); } BEGIN_METADATA(ExtensionsToolbarContainer, ToolbarIconContainerView)
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc index f35c487e..e696a81 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc
@@ -20,7 +20,7 @@ site_access_button_(AddChildView(std::move(site_access_button))), extensions_button_(extensions_button.get()) { site_access_button_->SetVisible(false); - request_access_button_->SetVisible(true); + request_access_button_->SetVisible(false); // TODO(emiliapaz): Consider changing AddMainItem() to receive a unique_ptr. AddMainItem(extensions_button.release()); } @@ -33,20 +33,29 @@ bool visibility) { site_access_button_->SetVisible(visibility); - // Layout animation does not handle host view visibility changing; requires - // resetting. - // TODO(crbug.com/1239772): Consider moving this to a separate method, or - // merging both visibility updates under one method after setting the request - // access button visibility based on extensions requesting access. - GetAnimatingLayoutManager()->ResetLayout(); + ResetLayout(); } void ExtensionsToolbarControls::UpdateRequestAccessButton( - const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions) { - // TODO(crbug.com/1239772): Display site access button, and add the action - // icons to the button and tooltip only when 1+ actions are given. For now, - // setting visible as true to see the button in the toolbar. - request_access_button_->SetVisible(true); + int count_requesting_extensions) { + if (count_requesting_extensions == 0) { + request_access_button_->SetVisible(false); + } else { + // TODO(crbug.com/1239772): Update icons, based on the number of extensions + // requesting access, once multiple icons in button is supported. Since we + // will need to access the extension information, this method may receive + // actions instead of actions count. For now, just show the number of + // actions. + request_access_button_->UpdateLabel(count_requesting_extensions); + request_access_button_->SetVisible(true); + // TODO(crbug.com/1239772): Update tooltip with the extension's names. + } + + ResetLayout(); +} + +void ExtensionsToolbarControls::ResetLayout() { + GetAnimatingLayoutManager()->ResetLayout(); } BEGIN_METADATA(ExtensionsToolbarControls, ToolbarIconContainerView)
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h index a1a92f1..f268863 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h
@@ -13,7 +13,6 @@ class ExtensionsToolbarButton; class ExtensionsRequestAccessButton; -class ToolbarActionViewController; class ExtensionsToolbarControls : public ToolbarIconContainerView { public: @@ -32,17 +31,24 @@ return extensions_button_; } + // Methods for testing. ExtensionsToolbarButton* site_access_button_for_testing() const { return site_access_button_; } + ExtensionsRequestAccessButton* request_access_button_for_testing() const { + return request_access_button_; + } // Updates `site_access_button_` visibility to the given one. void UpdateSiteAccessButtonVisibility(bool visibility); // Updates `request_access_button_` visibility and content based on the given - // `actions`. - void UpdateRequestAccessButton( - const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions); + // `count_requesting_extensions`. + void UpdateRequestAccessButton(int count_requesting_extensions); + + // Resets the layout since layout animation does not handle host view + // visibility changing. This should be called after any visibility changes. + void ResetLayout(); // ToolbarIconContainerView: void UpdateAllIcons() override;
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc index 43ae975..a01fa5c 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc
@@ -9,6 +9,9 @@ #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h" +#include "chrome/grit/generated_resources.h" +#include "content/public/browser/notification_service.h" +#include "extensions/browser/notification_types.h" #include "ui/views/view_utils.h" class ExtensionsToolbarControlsUnitTest : public ExtensionsToolbarUnitTest { @@ -20,6 +23,12 @@ const ExtensionsToolbarControlsUnitTest& operator=( const ExtensionsToolbarControlsUnitTest&) = delete; + ExtensionsRequestAccessButton* request_access_button(); + ExtensionsToolbarButton* site_access_button(); + + // Returns whether the request access button is visible or not. + bool IsRequestAccessButtonVisible(); + // Returns whether the site access button is visible or not. bool IsSiteAccessButtonVisible(); @@ -32,14 +41,26 @@ features::kExtensionsMenuAccessControl); } +ExtensionsRequestAccessButton* +ExtensionsToolbarControlsUnitTest::request_access_button() { + return extensions_container() + ->GetExtensionsToolbarControls() + ->request_access_button_for_testing(); +} + +ExtensionsToolbarButton* +ExtensionsToolbarControlsUnitTest::site_access_button() { + return extensions_container() + ->GetExtensionsToolbarControls() + ->site_access_button_for_testing(); +} + +bool ExtensionsToolbarControlsUnitTest::IsRequestAccessButtonVisible() { + return request_access_button()->GetVisible(); +} + bool ExtensionsToolbarControlsUnitTest::IsSiteAccessButtonVisible() { - for (auto* view : extensions_container()->children()) { - if (views::IsViewClass<ExtensionsToolbarControls>(view)) - return static_cast<ExtensionsToolbarControls*>(view) - ->site_access_button_for_testing() - ->GetVisible(); - } - return false; + return site_access_button()->GetVisible(); } TEST_F(ExtensionsToolbarControlsUnitTest, @@ -135,8 +156,132 @@ web_contents_tester->NavigateAndCommit(url_b); EXPECT_TRUE(IsSiteAccessButtonVisible()); - // Remove the only extension that has access to the current site. No extension - // should have access to the current site. - UninstallExtension(extension_all_urls->id()); - EXPECT_FALSE(IsSiteAccessButtonVisible()); + // TODO(crbug.com/1304959): Remove the only extension that requests access to + // the current site to verify no extension has access to the current + // site. Uninstall extension in unit tests is flaky. +} + +TEST_F(ExtensionsToolbarControlsUnitTest, + RequestAccessButtonVisibility_NavigationBetweenPages) { + content::WebContentsTester* web_contents_tester = + AddWebContentsAndGetTester(); + const GURL url_a("http://www.a.com"); + const GURL url_b("http://www.b.com"); + + // Add an extension that only requests access to a specific url, and withhold + // site access. + auto extension_a = + InstallExtensionWithHostPermissions("Extension A", {url_a.spec()}); + WithholdHostPermissions(extension_a.get()); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + + // Navigate to an url the extension requests access to. + web_contents_tester->NavigateAndCommit(url_a); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + EXPECT_EQ( + request_access_button()->GetText(), + l10n_util::GetStringFUTF16Int(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON, 1)); + + // Navigate to an url the extension does not request access to. + web_contents_tester->NavigateAndCommit(url_b); + EXPECT_FALSE(IsRequestAccessButtonVisible()); +} + +TEST_F(ExtensionsToolbarControlsUnitTest, + RequestAccessButtonVisibility_ContextMenuChangesHostPermissions) { + content::WebContentsTester* web_contents_tester = + AddWebContentsAndGetTester(); + const GURL url_a("http://www.a.com"); + const GURL url_b("http://www.b.com"); + + // Add an extension with all urls host permissions. Since we haven't navigated + // to an url yet, the extension should not request access. + auto extension = + InstallExtensionWithHostPermissions("Extension AllUrls", {"<all_urls>"}); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + + // Navigate to an url the extension should have access to as part of + // <all_urls>, since permissions are granted by default. + web_contents_tester->NavigateAndCommit(url_a); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + + extensions::ExtensionContextMenuModel context_menu( + extension.get(), browser(), extensions::ExtensionContextMenuModel::PINNED, + nullptr, true, + extensions::ExtensionContextMenuModel::ContextMenuSource::kToolbarAction); + + // Change the extension to run only on click using the context + // menu. The extension should request access to the current site. + { + content::WindowedNotificationObserver permissions_observer( + extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, + content::NotificationService::AllSources()); + context_menu.ExecuteCommand( + extensions::ExtensionContextMenuModel::PAGE_ACCESS_RUN_ON_CLICK, 0); + permissions_observer.Wait(); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + EXPECT_EQ( + request_access_button()->GetText(), + l10n_util::GetStringFUTF16Int(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON, 1)); + } + + // Change the extension to run only on site using the context + // menu. The extension should not request access to the current site. + { + content::WindowedNotificationObserver permissions_observer( + extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, + content::NotificationService::AllSources()); + context_menu.ExecuteCommand( + extensions::ExtensionContextMenuModel::PAGE_ACCESS_RUN_ON_SITE, 0); + permissions_observer.Wait(); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + } +} + +TEST_F(ExtensionsToolbarControlsUnitTest, + RequestAccessButtonVisibility_MultipleExtensions) { + content::WebContentsTester* web_contents_tester = + AddWebContentsAndGetTester(); + const GURL url_a("http://www.a.com"); + const GURL url_b("http://www.b.com"); + + // Navigate to a.com and since there are no extensions installed yet, no + // extension is requesting access to the current site. + web_contents_tester->NavigateAndCommit(url_a); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + + // Add an extension that doesn't request host permissions. + InstallExtension("no_permissions"); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + + // Add an extension that only requests access to a.com, and + // withhold host permissions. + auto extension_a = + InstallExtensionWithHostPermissions("Extension A", {url_a.spec()}); + WithholdHostPermissions(extension_a.get()); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + EXPECT_EQ( + request_access_button()->GetText(), + l10n_util::GetStringFUTF16Int(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON, 1)); + + // Add an extension with all urls host permissions, and withhold host + // permissions. + auto extension_all_urls = + InstallExtensionWithHostPermissions("Extension AllUrls", {"<all_urls>"}); + WithholdHostPermissions(extension_all_urls.get()); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + EXPECT_EQ( + request_access_button()->GetText(), + l10n_util::GetStringFUTF16Int(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON, 2)); + + // Navigate to a different url. Only "all_urls" should request access. + web_contents_tester->NavigateAndCommit(url_b); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + EXPECT_EQ( + request_access_button()->GetText(), + l10n_util::GetStringFUTF16Int(IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON, 1)); + + // TODO(crbug.com/1304959): Remove the only extension that requests access to + // the current site to verify no extension should have access to the current + // site. Uninstall extension in unit tests is flaky. }
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc index a6aaa30..136e7ba 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.cc
@@ -7,9 +7,12 @@ #include "base/run_loop.h" #include "build/build_config.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/scripting_permissions_modifier.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" #include "components/crx_file/id_util.h" +#include "content/public/browser/notification_service.h" +#include "extensions/browser/notification_types.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "extensions/common/value_builder.h" @@ -100,6 +103,16 @@ extension_id, extensions::disable_reason::DISABLE_USER_ACTION); } +void ExtensionsToolbarUnitTest::WithholdHostPermissions( + const extensions::Extension* extension) { + content::WindowedNotificationObserver permissions_observer( + extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, + content::NotificationService::AllSources()); + extensions::ScriptingPermissionsModifier(profile(), extension) + .RemoveAllGrantedHostPermissions(); + permissions_observer.Wait(); +} + void ExtensionsToolbarUnitTest::ClickButton(views::Button* button) const { ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h index ae79b440..db437b9 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h
@@ -61,6 +61,9 @@ // Disables the extension of the given `extension_id`. void DisableExtension(const extensions::ExtensionId& extension_id); + // Withhold all host permissions of the given `extension`. + void WithholdHostPermissions(const extensions::Extension* extension); + // Triggers the press and release event of the given `button`. void ClickButton(views::Button* button) const;
diff --git a/chrome/browser/ui/views/location_bar/intent_chip_button.cc b/chrome/browser/ui/views/location_bar/intent_chip_button.cc index 651f6e9..f97e76b 100644 --- a/chrome/browser/ui/views/location_bar/intent_chip_button.cc +++ b/chrome/browser/ui/views/location_bar/intent_chip_button.cc
@@ -42,12 +42,20 @@ bool collapsed = GetChipCollapsed(); ResetAnimation(!collapsed); SetTheme(collapsed ? Theme::kIconStyle : Theme::kLowVisibility); + UpdateIconAndColors(); } if (was_visible && !is_visible) IntentPickerBubbleView::CloseCurrentBubble(); } +ui::ImageModel IntentChipButton::GetIconImageModel() const { + auto icon = GetAppIcon(); + if (icon.IsEmpty()) + return OmniboxChipButton::GetIconImageModel(); + return icon; +} + bool IntentChipButton::GetShowChip() const { if (delegate_->ShouldHidePageActionIcons()) return false; @@ -61,6 +69,12 @@ return tab_helper && tab_helper->should_show_collapsed_chip(); } +ui::ImageModel IntentChipButton::GetAppIcon() const { + if (auto* tab_helper = GetTabHelper()) + return tab_helper->app_icon(); + return ui::ImageModel(); +} + void IntentChipButton::HandlePressed() { content::WebContents* web_contents = delegate_->GetWebContentsForPageActionIconView();
diff --git a/chrome/browser/ui/views/location_bar/intent_chip_button.h b/chrome/browser/ui/views/location_bar/intent_chip_button.h index 82663f0..84485d94 100644 --- a/chrome/browser/ui/views/location_bar/intent_chip_button.h +++ b/chrome/browser/ui/views/location_bar/intent_chip_button.h
@@ -31,10 +31,14 @@ private: bool GetShowChip() const; bool GetChipCollapsed() const; + ui::ImageModel GetAppIcon() const; void HandlePressed(); IntentPickerTabHelper* GetTabHelper() const; + // OmniboxChipButton: + ui::ImageModel GetIconImageModel() const override; + const raw_ptr<Browser> browser_; const raw_ptr<PageActionIconView::Delegate> delegate_; };
diff --git a/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc b/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc index 8cf90faf..31ba53d 100644 --- a/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
@@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/apps/intent_helper/intent_picker_features.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/intent_picker_tab_helper.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" #include "chrome/browser/ui/views/location_bar/intent_chip_button.h" @@ -14,7 +16,9 @@ #include "chrome/browser/ui/web_applications/test/web_app_navigation_browsertest.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_install_info.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" +#include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event_utils.h" #include "ui/views/test/button_test_api.h" #include "ui/views/widget/any_widget_observer.h" @@ -70,6 +74,20 @@ return true; } + // Installs a web app on the same host as InstallTestWebApp(), but with "/" as + // a scope, so it overlaps with all URLs in the test app scope. + void InstallOverlappingApp() { + auto web_app_info = std::make_unique<WebAppInstallInfo>(); + const char* app_host = GetAppUrlHost(); + web_app_info->start_url = https_server().GetURL(app_host, "/"); + web_app_info->scope = https_server().GetURL(app_host, "/"); + web_app_info->title = base::UTF8ToUTF16(GetAppName()); + web_app_info->description = u"Test description"; + web_app_info->user_display_mode = blink::mojom::DisplayMode::kStandalone; + + web_app::test::InstallWebApp(profile(), std::move(web_app_info)); + } + private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -77,7 +95,7 @@ IN_PROC_BROWSER_TEST_F(IntentChipButtonBrowserTest, NavigationToInScopeLinkShowsIntentChip) { if (!HasRequiredAshVersionForLacros()) - return; + GTEST_SKIP() << "Ash version is too old to support Intent Picker"; InstallTestWebApp(); @@ -101,7 +119,7 @@ IN_PROC_BROWSER_TEST_F(IntentChipButtonBrowserTest, NavigationToOutOfScopeLinkDoesNotShowsIntentChip) { if (!HasRequiredAshVersionForLacros()) - return; + GTEST_SKIP() << "Ash version is too old to support Intent Picker"; InstallTestWebApp(); @@ -117,7 +135,7 @@ IN_PROC_BROWSER_TEST_F(IntentChipButtonBrowserTest, IconVisibilityAfterTabSwitching) { if (!HasRequiredAshVersionForLacros()) - return; + GTEST_SKIP() << "Ash version is too old to support Intent Picker"; InstallTestWebApp(); @@ -151,20 +169,10 @@ IN_PROC_BROWSER_TEST_F(IntentChipButtonBrowserTest, MAYBE_ShowsIntentPickerWhenMultipleApps) { if (!HasRequiredAshVersionForLacros()) - return; + GTEST_SKIP() << "Ash version is too old to support Intent Picker"; InstallTestWebApp(); - - // Install a second app with a different start URL and an overlapping scope. - auto web_app_info = std::make_unique<WebAppInstallInfo>(); - const char* app_host = GetAppUrlHost(); - web_app_info->start_url = https_server().GetURL(app_host, "/"); - web_app_info->scope = https_server().GetURL(app_host, "/"); - web_app_info->title = base::UTF8ToUTF16(GetAppName()); - web_app_info->description = u"Test description"; - web_app_info->user_display_mode = blink::mojom::DisplayMode::kStandalone; - - web_app::test::InstallWebApp(profile(), std::move(web_app_info)); + InstallOverlappingApp(); const GURL in_scope_url = https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); @@ -188,7 +196,7 @@ IN_PROC_BROWSER_TEST_F(IntentChipButtonBrowserTest, ShowsIntentChipCollapsed) { if (!HasRequiredAshVersionForLacros()) - return; + GTEST_SKIP() << "Ash version is too old to support Intent Picker"; InstallTestWebApp(); @@ -244,3 +252,67 @@ EXPECT_TRUE(GetIntentChip()->GetVisible()); EXPECT_FALSE(GetIntentChip()->is_fully_collapsed()); } + +class IntentChipButtonAppIconBrowserTest : public IntentChipButtonBrowserTest { + public: + IntentChipButtonAppIconBrowserTest() { + feature_list_.InitAndEnableFeature(apps::features::kIntentChipAppIcon); + } + + void ClickLinkAndWaitForIconUpdate(content::WebContents* web_contents, + const GURL& link_url) { + auto* tab_helper = IntentPickerTabHelper::FromWebContents(web_contents); + base::RunLoop run_loop; + tab_helper->SetIconUpdateCallbackForTesting( + base::BindLambdaForTesting([&run_loop]() { run_loop.Quit(); })); + + ClickLinkAndWait(web_contents, link_url, LinkTarget::SELF, ""); + + run_loop.Run(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(IntentChipButtonAppIconBrowserTest, ShowsAppIconInChip) { + if (!HasRequiredAshVersionForLacros()) + GTEST_SKIP() << "Ash version is too old to support Intent Picker"; + + InstallTestWebApp(); + InstallOverlappingApp(); + + const GURL root_url = https_server().GetURL(GetAppUrlHost(), "/"); + const GURL overlapped_url = + https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); + const GURL non_overlapped_url = + https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + ClickLinkAndWaitForIconUpdate(web_contents, root_url); + + auto icon1 = + GetIntentChip()->GetImage(views::Button::ButtonState::STATE_NORMAL); + ASSERT_FALSE(IntentPickerTabHelper::FromWebContents(web_contents) + ->app_icon() + .IsEmpty()); + + ClickLinkAndWaitForIconUpdate(web_contents, non_overlapped_url); + + // The chip should still be showing the same app icon. + auto icon2 = + GetIntentChip()->GetImage(views::Button::ButtonState::STATE_NORMAL); + ASSERT_TRUE(icon1.BackedBySameObjectAs(icon2)); + + ClickLinkAndWaitForIconUpdate(web_contents, overlapped_url); + + // Loading a URL with multiple apps available should switch to a generic icon. + auto icon3 = + GetIntentChip()->GetImage(views::Button::ButtonState::STATE_NORMAL); + ASSERT_FALSE(icon1.BackedBySameObjectAs(icon3)); + ASSERT_TRUE(IntentPickerTabHelper::FromWebContents(web_contents) + ->app_icon() + .IsEmpty()); +}
diff --git a/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc b/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc index e1a0b45..6b550826 100644 --- a/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc +++ b/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc
@@ -125,6 +125,12 @@ UpdateIconAndColors(); } +ui::ImageModel OmniboxChipButton::GetIconImageModel() const { + return ui::ImageModel::FromVectorIcon( + show_blocked_icon_ ? icon_off_ : icon_on_, GetTextAndIconColor(), + GetIconSize(), nullptr); +} + int OmniboxChipButton::GetIconSize() const { return GetLayoutConstant(LOCATION_BAR_ICON_SIZE); } @@ -133,10 +139,7 @@ if (!GetWidget()) return; SetEnabledTextColors(GetTextAndIconColor()); - SetImageModel(views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon( - show_blocked_icon_ ? icon_off_ : icon_on_, - GetTextAndIconColor(), GetIconSize(), nullptr)); + SetImageModel(views::Button::STATE_NORMAL, GetIconImageModel()); } SkColor OmniboxChipButton::GetTextAndIconColor() const {
diff --git a/chrome/browser/ui/views/location_bar/omnibox_chip_button.h b/chrome/browser/ui/views/location_bar/omnibox_chip_button.h index da535e4..21e1488 100644 --- a/chrome/browser/ui/views/location_bar/omnibox_chip_button.h +++ b/chrome/browser/ui/views/location_bar/omnibox_chip_button.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_OMNIBOX_CHIP_BUTTON_H_ #include "ui/base/metadata/metadata_header_macros.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/views/controls/button/md_text_button.h" @@ -60,13 +61,15 @@ Theme get_theme_for_testing() { return theme_; } - private: - int GetIconSize() const; - + protected: + virtual ui::ImageModel GetIconImageModel() const; // Updates the icon, and then updates text, icon, and background colors from // the theme. void UpdateIconAndColors(); + private: + int GetIconSize() const; + SkColor GetTextAndIconColor() const; SkColor GetBackgroundColor() const;
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_access_code_cast_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_access_code_cast_button.cc index 325c4f5..40439bd 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_access_code_cast_button.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_access_code_cast_button.cc
@@ -25,7 +25,7 @@ std::unique_ptr<views::ImageView> CreatePrimaryIconView() { auto icon_view = std::make_unique<views::ImageView>(); icon_view->SetImage(ui::ImageModel::FromVectorIcon( - vector_icons::kQrCodeIcon, ui::kColorIcon, kPrimaryIconSize)); + vector_icons::kKeyboardIcon, ui::kColorIcon, kPrimaryIconSize)); icon_view->SetBorder(views::CreateEmptyBorder(kPrimaryIconBorder)); return icon_view; }
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc index b204ca1..b6f4e08c 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -511,6 +511,7 @@ } void WebAppIntegrationTestDriver::TearDownOnMainThread() { + LOG(INFO) << "TearDownOnMainThread: Start."; observation_.Reset(); if (delegate_->IsSyncTest()) SyncTurnOff(); @@ -519,6 +520,7 @@ base::RunLoop run_loop; std::vector<AppId> app_ids = provider->registrar().GetAppIds(); for (auto& app_id : app_ids) { + LOG(INFO) << "TearDownOnMainThread: Uninstalling " << app_id << "."; const WebApp* app = provider->registrar().GetAppById(app_id); if (app->IsPolicyInstalledApp()) UninstallPolicyAppById(app_id); @@ -532,11 +534,13 @@ })); run_loop.Run(); } + LOG(INFO) << "TearDownOnMainThread: Uninstall complete."; } // TODO(crbug.com/1273568): Investigate the true source of flakiness instead // of papering over it here. FlushShortcutTasks(); } + LOG(INFO) << "TearDownOnMainThread: Deleting dangling shortcuts."; // TODO(crbug.com/1273568): Investigate the true source of flakiness instead of // papering over it here. #if BUILDFLAG(IS_WIN) @@ -551,6 +555,7 @@ if (shortcut_override_->desktop.IsValid()) ASSERT_TRUE(shortcut_override_->desktop.Delete()); #endif + LOG(INFO) << "TearDownOnMainThread: Complete."; } void WebAppIntegrationTestDriver::AcceptAppIdUpdateDialog() {
diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.cc b/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.cc index 4bf1c64..d8d42d0 100644 --- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.cc +++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.cc
@@ -290,7 +290,7 @@ // QueryManager observer that alerts the handler about the availability of // newly discovered sinks, as well as what types of casting those sinks support. -void AccessCodeCastHandler::OnResultsUpdated( +void AccessCodeCastHandler::OnSinksUpdated( const std::vector<MediaSinkWithCastModes>& sinks) { if (add_sink_callback_ && sink_id_) { media_router_->GetLogger()->LogInfo(
diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.h b/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.h index a07fd5e..8b3e3ad 100644 --- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.h +++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler.h
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/media_router/media_cast_mode.h" #include "chrome/browser/ui/media_router/media_router_ui.h" #include "chrome/browser/ui/media_router/media_router_ui_helper.h" +#include "chrome/browser/ui/media_router/media_sink_with_cast_modes_observer.h" #include "chrome/browser/ui/media_router/query_result_manager.h" #include "chrome/browser/ui/webui/access_code_cast/access_code_cast.mojom.h" #include "components/media_router/browser/presentation/start_presentation_context.h" @@ -41,7 +42,7 @@ namespace media_router { class AccessCodeCastHandler : public access_code_cast::mojom::PageHandler, - public QueryResultManager::Observer, + public MediaSinkWithCastModesObserver, public WebContentsPresentationManager::Observer { public: using DiscoveryDevice = chrome_browser_media::proto::DiscoveryDevice; @@ -102,8 +103,8 @@ access_code_cast::mojom::AddSinkResultCode add_sink_result, absl::optional<MediaSink::Id> sink_id); - // QueryResultManager::Observer: - void OnResultsUpdated( + // MediaSinkWithCastModesObserver: + void OnSinksUpdated( const std::vector<MediaSinkWithCastModes>& sinks) override; // WebContentsPresentationManager::Observer
diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler_unittest.cc b/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler_unittest.cc index 95462cb..9611acd 100644 --- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler_unittest.cc +++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_handler_unittest.cc
@@ -75,10 +75,13 @@ MockAccessCodeCastSinkService( Profile* profile, MediaRouter* media_router, - CastMediaSinkServiceImpl* cast_media_sink_service_impl) + CastMediaSinkServiceImpl* cast_media_sink_service_impl, + DiscoveryNetworkMonitor* network_monitor) : AccessCodeCastSinkService(profile, media_router, - cast_media_sink_service_impl) {} + cast_media_sink_service_impl, + network_monitor, + profile->GetPrefs()) {} ~MockAccessCodeCastSinkService() override = default; MOCK_METHOD(void, @@ -148,7 +151,8 @@ access_code_cast_sink_service_ = std::make_unique<MockAccessCodeCastSinkService>( - profile_, router_, mock_cast_media_sink_service_impl_.get()); + profile_, router_, mock_cast_media_sink_service_impl_.get(), + discovery_network_monitor_.get()); access_code_cast_sink_service_->SetTaskRunnerForTest( mock_time_task_runner_); @@ -369,7 +373,7 @@ sink_with_cast_modes.cast_modes = {MediaCastMode::DESKTOP_MIRROR}; handler()->set_sink_id_for_testing(cast_sink_1().sink().id()); - handler()->OnResultsUpdated({sink_with_cast_modes}); + handler()->OnSinksUpdated({sink_with_cast_modes}); } // Demonstrates that if handler is notified about a device other than the @@ -384,7 +388,7 @@ MediaSinkWithCastModes sink_with_cast_modes(cast_sink_2().sink()); sink_with_cast_modes.cast_modes = {MediaCastMode::DESKTOP_MIRROR}; - handler()->OnResultsUpdated({sink_with_cast_modes}); + handler()->OnSinksUpdated({sink_with_cast_modes}); } // Demonstrates that desktop mirroring attempts call media router with the
diff --git a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc index c78525f..8bf6d80 100644 --- a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc +++ b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc
@@ -8,8 +8,8 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" +#include "content/public/browser/webui_config_map.h" #include "printing/buildflags/buildflags.h" -#include "ui/webui/webui_config_map.h" #if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/ui/webui/print_preview/print_preview_ui_untrusted.h" @@ -41,7 +41,7 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) void RegisterChromeUntrustedWebUIConfigs() { - auto& map = ui::WebUIConfigMap::GetInstance(); + auto& map = content::WebUIConfigMap::GetInstance(); // Register WebUIConfigs below. #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc index b1f346e..d3215d2 100644 --- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc +++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -25,6 +25,7 @@ #include "chrome/grit/assistant_optin_resources.h" #include "chrome/grit/assistant_optin_resources_map.h" #include "chrome/grit/browser_resources.h" +#include "chrome/grit/oobe_conditional_resources.h" #include "chromeos/assistant/buildflags.h" #include "chromeos/services/assistant/public/cpp/assistant_prefs.h" #include "chromeos/services/assistant/public/cpp/features.h" @@ -88,7 +89,8 @@ source->UseStringsJs(); source->AddResourcePaths( base::make_span(kAssistantOptinResources, kAssistantOptinResourcesSize)); - source->SetDefaultResource(IDR_ASSISTANT_OPTIN_ASSISTANT_OPTIN_HTML); + source->AddResourcePath("assistant_optin.js", IDR_ASSISTANT_OPTIN_JS); + source->SetDefaultResource(IDR_ASSISTANT_OPTIN_HTML); source->AddResourcePath("voice_match_animation.json", IDR_ASSISTANT_VOICE_MATCH_ANIMATION); source->OverrideContentSecurityPolicy(
diff --git a/chrome/browser/web_applications/app_service/lacros_web_apps_controller_lacros_browsertest.cc b/chrome/browser/web_applications/app_service/lacros_web_apps_controller_lacros_browsertest.cc index 194247b..a97dabe 100644 --- a/chrome/browser/web_applications/app_service/lacros_web_apps_controller_lacros_browsertest.cc +++ b/chrome/browser/web_applications/app_service/lacros_web_apps_controller_lacros_browsertest.cc
@@ -4,6 +4,7 @@ #include "base/callback_helpers.h" #include "base/logging.h" +#include "base/test/bind.h" #include "chrome/browser/lacros/browser_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" @@ -41,7 +42,7 @@ return service->GetInterfaceVersion( crosapi::mojom::TestController::Uuid_) >= static_cast<int>(crosapi::mojom::TestController::MethodMinVersions:: - kDoesItemExistInShelfMinVersion); + kCloseAllBrowserWindowsMinVersion); } }; @@ -116,6 +117,25 @@ // Settings should now exist in the shelf. browser_test_util::WaitForShelfItem(kOsSettingsAppId, /*exists=*/true); + + base::RunLoop run_loop; + auto* const lacros_service = chromeos::LacrosService::Get(); + lacros_service->GetRemote<crosapi::mojom::TestController>() + ->CloseAllBrowserWindows( + base::BindLambdaForTesting([&run_loop](bool success) { + EXPECT_TRUE(success); + run_loop.Quit(); + })); + run_loop.Run(); + + // Settings should no longer exist in the shelf. + browser_test_util::WaitForShelfItem(kOsSettingsAppId, /*exists=*/false); + + // Close app window. + browser->window()->Close(); + + // Wait for item to stop existing in shelf. + browser_test_util::WaitForShelfItem(app_id, /*exists=*/false); } } // namespace web_app
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 59481c6..ddb9127a 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1649267980-fcb73c50ddd596f4d25522a13277eda2b628968e.profdata +chrome-linux-main-1649289578-fe71f71af9afbec36ec003ab2700468ff94f2d05.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 398281c..ab711ca 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1649267980-67b7e74232abea5aa56fb85997bdf64524c25b53.profdata +chrome-mac-arm-main-1649289578-a7a9c144775f8c87a5e245f56507f984cbcab9fe.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 172b7bbb..a422636 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1649267980-ab5c5b955fc28e8b0020a1379f3e4eed04acf00e.profdata +chrome-win32-main-1649278527-46a91bf9bffccc5a0271d7ea73e46552f392ae75.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 408fd8b2..890eaa49 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1649267980-8e94e879798a9ee01e80cc15f94b0afa7c1c39d9.profdata +chrome-win64-main-1649278527-caa58b598d5561560c9ab7be6a6f2671dd1bd9e4.profdata
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 7086278..baf033af 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -446,13 +446,6 @@ // Pref storing the user's network easter egg game high score. const char kNetworkEasterEggHighScore[] = "net.easter_egg_high_score"; -#if BUILDFLAG(IS_ANDROID) -// Last time that a check for cloud policy management was done. This time is -// recorded on Android so that retries aren't attempted on every startup. -// Instead the cloud policy registration is retried at least 1 or 3 days later. -const char kLastPolicyCheckTime[] = "policy.last_policy_check_time"; -#endif - // A preference of enum chrome_browser_net::NetworkPredictionOptions shows // if prediction of network actions is allowed, depending on network type. // Actions include DNS prefetching, TCP and SSL preconnection, prerendering
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 574a6917..21b5275 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -199,9 +199,6 @@ extern const char kQuicAllowed[]; extern const char kNetworkQualities[]; extern const char kNetworkEasterEggHighScore[]; -#if BUILDFLAG(IS_ANDROID) -extern const char kLastPolicyCheckTime[]; -#endif extern const char kNetworkPredictionOptions[]; extern const char kPreinstalledAppsInstallState[]; extern const char kHideWebStoreIcon[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index f04d3f3..cc4b5ca3 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3854,7 +3854,6 @@ "//chrome", "//chrome/test/data/webui/cr_components/chromeos/cellular_setup:modulize_runtime_data", "//chrome/test/data/webui/nearby_share/shared:modulize_runtime_data", - "//chrome/test/data/webui/settings/chromeos:modulize_runtime_data", "//testing/buildbot/filters:chromeos_filters", "//ui/file_manager:unit_test_data", ] @@ -8204,6 +8203,7 @@ sources += [ "../../ui/views/controls/webview/web_dialog_view_unittest.cc", "../../ui/views/controls/webview/webview_unittest.cc", + "../browser/ui/media_router/media_route_starter_unittest.cc", "../browser/ui/media_router/media_router_ui_unittest.cc", "../browser/ui/user_education/feature_promo_snooze_service_unittest.cc", "../browser/ui/user_education/tutorial/tutorial_unittest.cc",
diff --git a/chrome/test/base/chrome_unit_test_suite.cc b/chrome/test/base/chrome_unit_test_suite.cc index 4c6e121..0a58574 100644 --- a/chrome/test/base/chrome_unit_test_suite.cc +++ b/chrome/test/base/chrome_unit_test_suite.cc
@@ -22,6 +22,7 @@ #include "components/component_updater/component_updater_paths.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" #include "components/update_client/update_query_params.h" +#include "content/public/browser/webui_config_map.h" #include "content/public/common/content_paths.h" #include "content/public/test/scoped_web_ui_controller_factory_registration.h" #include "extensions/buildflags/buildflags.h" @@ -32,7 +33,6 @@ #include "ui/base/resource/resource_handle.h" #include "ui/base/ui_base_paths.h" #include "ui/gl/test/gl_surface_test_support.h" -#include "ui/webui/webui_config_map.h" #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) #include "chromeos/dbus/constants/dbus_paths.h" @@ -163,7 +163,7 @@ content::WebUIControllerFactory::RegisterFactory( ChromeWebUIControllerFactory::GetInstance()); // Ensure the WebUIConfigMap registers its WebUIControllerFactory. - ui::WebUIConfigMap::GetInstance(); + content::WebUIConfigMap::GetInstance(); gl::GLSurfaceTestSupport::InitializeOneOff();
diff --git a/chrome/test/data/system_extensions/basic_system_extension/sw.js b/chrome/test/data/system_extensions/basic_system_extension/sw.js new file mode 100644 index 0000000..0a281cc --- /dev/null +++ b/chrome/test/data/system_extensions/basic_system_extension/sw.js
@@ -0,0 +1,5 @@ +// Copyright 2022 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. + +console.log("registered");
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 045c5a9..c56fbf9 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -272,16 +272,6 @@ "$root_gen_dir/chrome/test/data/webui/nearby_share/shared/nearby_onboarding_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/nearby_share/shared/nearby_page_template_test.m.js", "$root_gen_dir/chrome/test/data/webui/nearby_share/shared/nearby_visibility_page_test.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/onc_mojo_test.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/kerberos_page_test.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_os_lifetime_browser_proxy.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_personalization_hub_browser_proxy.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.m.js", - "$root_gen_dir/chrome/test/data/webui/settings/chromeos/tether_connection_dialog_test.m.js", ] } defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] @@ -364,7 +354,6 @@ deps = [ "./cr_components/chromeos:modulize", "./nearby_share/shared:modulize", - "./settings/chromeos:modulize", ] } }
diff --git a/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js b/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js index 601688e..41e940d 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js +++ b/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js
@@ -4,14 +4,17 @@ import 'chrome://diagnostics/input_list.js'; -import {ConnectionType, KeyboardInfo, MechanicalLayout, NumberPadPresence, PhysicalLayout, TopRightKey, TopRowKey, TouchDeviceInfo, TouchDeviceType} from 'chrome://diagnostics/diagnostics_types.js'; +import {DiagnosticsBrowserProxyImpl} from 'chrome://diagnostics/diagnostics_browser_proxy.js'; +import {ConnectionType, KeyboardInfo, MechanicalLayout, NavigationView, NumberPadPresence, PhysicalLayout, TopRightKey, TopRowKey, TouchDeviceInfo, TouchDeviceType} from 'chrome://diagnostics/diagnostics_types.js'; import {fakeKeyboards, fakeTouchDevices} from 'chrome://diagnostics/fake_data.js'; import {FakeInputDataProvider} from 'chrome://diagnostics/fake_input_data_provider.js'; import {setInputDataProviderForTesting} from 'chrome://diagnostics/mojo_interface_provider.js'; -import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; +import {assertArrayEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; import {flushTasks} from '../../test_util.js'; +import {TestDiagnosticsBrowserProxy} from './test_diagnostics_browser_proxy.js'; + export function inputListTestSuite() { /** @type {?InputListElement} */ let inputListElement = null; @@ -19,9 +22,15 @@ /** @type {?FakeInputDataProvider} */ let provider = null; + /** @type {?TestDiagnosticsBrowserProxy} */ + let diagnosticsBrowserProxy = null; + suiteSetup(() => { provider = new FakeInputDataProvider(); setInputDataProviderForTesting(provider); + + diagnosticsBrowserProxy = new TestDiagnosticsBrowserProxy(); + DiagnosticsBrowserProxyImpl.instance_ = diagnosticsBrowserProxy; }); setup(() => { @@ -198,4 +207,22 @@ assertFalse(isVisible(getCardByDeviceType('touchpad'))); assertFalse(isVisible(getCardByDeviceType('touchscreen'))); }); + + test('RecordNavigationCalled', async () => { + await initializeInputList(); + inputListElement.onNavigationPageChanged({isActive: false}); + await flushTasks(); + + assertEquals(0, diagnosticsBrowserProxy.getCallCount('recordNavigation')); + + diagnosticsBrowserProxy.setPreviousView(NavigationView.kSystem); + inputListElement.onNavigationPageChanged({isActive: true}); + + await flushTasks(); + assertEquals(1, diagnosticsBrowserProxy.getCallCount('recordNavigation')); + assertArrayEquals( + [NavigationView.kSystem, NavigationView.kInput], + /** @type {!Array<!NavigationView>} */ + (diagnosticsBrowserProxy.getArgs('recordNavigation')[0])); + }); }
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js index a8a0513..3941fe7 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js
@@ -682,6 +682,22 @@ }); }); + test('SetGetPowerwashRequiredResultTrueUpdatesResult', () => { + service.setGetPowerwashRequiredResult(true); + + return service.getPowerwashRequired().then((result) => { + assertEquals(true, result.powerwashRequired); + }); + }); + + test('SetGetPowerwashRequiredResultFalseUpdatesResult', () => { + service.setGetPowerwashRequiredResult(false); + + return service.getPowerwashRequired().then((result) => { + assertEquals(false, result.powerwashRequired); + }); + }); + test('EndRmaAndRebootOk', () => { let states = [ {state: State.kRepairComplete, error: RmadErrorCode.kOk},
diff --git a/chrome/test/data/webui/cr_elements/cr_a11y_announcer_test.ts b/chrome/test/data/webui/cr_elements/cr_a11y_announcer_test.ts index f60c017..ca21f6d0 100644 --- a/chrome/test/data/webui/cr_elements/cr_a11y_announcer_test.ts +++ b/chrome/test/data/webui/cr_elements/cr_a11y_announcer_test.ts
@@ -5,8 +5,8 @@ import 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js'; import {CrA11yAnnouncerElement, TIMEOUT_MS} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js'; - import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {eventToPromise} from 'chrome://webui-test/test_util.js'; suite('CrA11yAnnouncerElementTest', () => { setup(() => { @@ -60,4 +60,17 @@ // Creates new announcer since previous announcer is removed from instances. assertNotEquals(announcer, CrA11yAnnouncerElement.getInstance()); }); + + test('SendsCustomEvent', async () => { + const announcer = CrA11yAnnouncerElement.getInstance(); + const announcerEventPromise = + eventToPromise('cr-a11y-announcer-messages-sent', document.body); + const message1 = 'Hello.'; + const message2 = 'Hi.'; + announcer.announce(message1); + announcer.announce(message2); + const announcerEvent = await announcerEventPromise; + assertTrue(announcerEvent.detail.messages.includes(message1)); + assertTrue(announcerEvent.detail.messages.includes(message2)); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn index 439d4f16..43857e0 100644 --- a/chrome/test/data/webui/settings/chromeos/BUILD.gn +++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -2,12 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//chrome/browser/resources/nearby_share/shared/nearby_shared.gni") import("//chrome/browser/resources/settings/chromeos/os_settings.gni") import("//third_party/closure_compiler/compile_js.gni") -import("//tools/polymer/polymer.gni") -import("//ui/webui/resources/tools/js_modulizer.gni") -import("./os_namespace_rewrites.gni") js_type_check("closure_compile") { deps = [ @@ -29,36 +25,3 @@ "//ui/webui/resources/js:cr", ] } - -js_modulizer("modulize") { - input_files = [ - "fake_system_display.js", - "kerberos_accounts_test.js", - "kerberos_page_test.js", - "onc_mojo_test.js", - "smb_shares_page_tests.js", - "test_kerberos_accounts_browser_proxy.js", - "test_os_lifetime_browser_proxy.js", - "test_os_reset_browser_proxy.js", - "test_personalization_hub_browser_proxy.js", - "test_wallpaper_browser_proxy.js", - "tether_connection_dialog_test.js", - ] - namespace_rewrites = - os_settings_namespace_rewrites + os_test_namespace_rewrites + - nearby_shared_namespace_rewrites + - [ - "nearby_share.FakeNearbyShareSettings|FakeNearbyShareSettings", - "nearby_share.setReceiveManagerForTesting|setReceiveManagerForTesting", - "nearby_share.FakeReceiveManager|FakeReceiveManager", - "nearby_share.FakeContactManager|FakeContactManager", - "test_util.isVisible|isVisible", - "test_util.waitAfterNextRender|waitAfterNextRender", - "app_management.TestAppManagementStore|TestAppManagementStore", - "cr.ui.TestStore|TestStore", - "app_management.convertOptionalBoolToBool|convertOptionalBoolToBool", - "app_management.actions.changePage|changePage", - "settings.FakeSystemDisplay|FakeSystemDisplay", - "settings.setDisplayApiForTesting|setDisplayApiForTesting", - ] -}
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index eb3e07c..12a2587 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -14,7 +14,7 @@ import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; -import {FakeSystemDisplay} from './fake_system_display.m.js'; +import {FakeSystemDisplay} from './fake_system_display.js'; /** @enum {string} */ const TestNames = {
diff --git a/chrome/test/data/webui/settings/chromeos/fake_system_display.js b/chrome/test/data/webui/settings/chromeos/fake_system_display.js index 7f43e739..67689016 100644 --- a/chrome/test/data/webui/settings/chromeos/fake_system_display.js +++ b/chrome/test/data/webui/settings/chromeos/fake_system_display.js
@@ -2,166 +2,161 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// clang-format off -// #import {FakeChromeEvent} from '../../fake_chrome_event.js'; -// #import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; -// #import {assert} from 'chrome://resources/js/assert.m.js'; -// clang-format on +import {assert} from 'chrome://resources/js/assert.m.js'; +import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; + +import {FakeChromeEvent} from '../../fake_chrome_event.js'; + /** * @fileoverview Fake implementation of chrome.system.display for testing. */ -cr.define('settings', function() { +/** + * Fake of the chrome.settings.display API. + * @constructor + * @implements {SystemDisplay} + */ +export function FakeSystemDisplay() { + /** @type {!Array<!chrome.system.display.DisplayUnitInfo>} */ + this.fakeDisplays = []; + this.fakeLayouts = []; + this.getInfoCalled = new PromiseResolver(); + this.getLayoutCalled = new PromiseResolver(); +} + +FakeSystemDisplay.prototype = { + // Public testing methods. /** - * Fake of the chrome.settings.display API. - * @constructor - * @implements {SystemDisplay} + * @param {!chrome.system.display.DisplayUnitInfo>} display */ - /* #export */ function FakeSystemDisplay() { - /** @type {!Array<!chrome.system.display.DisplayUnitInfo>} */ - this.fakeDisplays = []; - this.fakeLayouts = []; - this.getInfoCalled = new PromiseResolver(); - this.getLayoutCalled = new PromiseResolver(); - } + addDisplayForTest: function(display) { + this.fakeDisplays.push(display); + this.updateLayouts_(); + }, - FakeSystemDisplay.prototype = { - // Public testing methods. - /** - * @param {!chrome.system.display.DisplayUnitInfo>} display - */ - addDisplayForTest: function(display) { - this.fakeDisplays.push(display); - this.updateLayouts_(); - }, - - // SystemDisplay overrides. - /** @override */ - getInfo: function(flags, callback) { - setTimeout(function() { - // Create a shallow copy to trigger Polymer data binding updates. - let displays; - if (this.fakeDisplays.length > 0 && - this.fakeDisplays[0].mirroringSourceId) { - // When mirroring is enabled, send only the info for the display - // being mirrored. - const display = - this.getFakeDisplay_(this.fakeDisplays[0].mirroringSourceId); - assert(!!display); - displays = [display]; - } else { - displays = this.fakeDisplays.slice(); - } - callback(displays); - this.getInfoCalled.resolve(); - // Reset the promise resolver. - this.getInfoCalled = new PromiseResolver(); - }.bind(this)); - }, - - /** @override */ - setDisplayProperties: function(id, info, callback) { - const display = this.getFakeDisplay_(id); - if (!display) { - chrome.runtime.lastError = 'Display not found.'; - callback(); + // SystemDisplay overrides. + /** @override */ + getInfo: function(flags, callback) { + setTimeout(function() { + // Create a shallow copy to trigger Polymer data binding updates. + let displays; + if (this.fakeDisplays.length > 0 && + this.fakeDisplays[0].mirroringSourceId) { + // When mirroring is enabled, send only the info for the display + // being mirrored. + const display = + this.getFakeDisplay_(this.fakeDisplays[0].mirroringSourceId); + assert(!!display); + displays = [display]; + } else { + displays = this.fakeDisplays.slice(); } + callback(displays); + this.getInfoCalled.resolve(); + // Reset the promise resolver. + this.getInfoCalled = new PromiseResolver(); + }.bind(this)); + }, - if (info.mirroringSourceId !== undefined) { - for (const d of this.fakeDisplays) { - d.mirroringSourceId = info.mirroringSourceId; - } - } - - if (info.isPrimary !== undefined) { - let havePrimary = info.isPrimary; - for (const d of this.fakeDisplays) { - if (d.id === id) { - d.isPrimary = info.isPrimary; - } else if (havePrimary) { - d.isPrimary = false; - } else { - d.isPrimary = true; - havePrimary = true; - } - } - this.updateLayouts_(); - } - if (info.rotation !== undefined) { - display.rotation = info.rotation; - } - }, - - /** @override */ - getDisplayLayout(callback) { - setTimeout(function() { - // Create a shallow copy to trigger Polymer data binding updates. - callback(this.fakeLayouts.slice()); - this.getLayoutCalled.resolve(); - // Reset the promise resolver. - this.getLayoutCalled = new PromiseResolver(); - }.bind(this)); - }, - - /** @override */ - setDisplayLayout(layouts, callback) { - this.fakeLayouts = layouts; + /** @override */ + setDisplayProperties: function(id, info, callback) { + const display = this.getFakeDisplay_(id); + if (!display) { + chrome.runtime.lastError = 'Display not found.'; callback(); - }, + } - /** @override */ - setMirrorMode(info, callback) { - let mirroringSourceId = ''; - if (info.mode === chrome.system.display.MirrorMode.NORMAL) { - // Select the primary display as the mirroring source. - for (const d of this.fakeDisplays) { - if (d.isPrimary) { - mirroringSourceId = d.id; - break; - } - } - } + if (info.mirroringSourceId !== undefined) { for (const d of this.fakeDisplays) { - d.mirroringSourceId = mirroringSourceId; + d.mirroringSourceId = info.mirroringSourceId; } - callback(); - }, + } - /** @override */ - onDisplayChanged: new FakeChromeEvent(), - - /** @private */ - getFakeDisplay_(id) { - const idx = this.fakeDisplays.findIndex(function(display) { - return display.id === id; - }); - if (idx >= 0) { - return this.fakeDisplays[idx]; + if (info.isPrimary !== undefined) { + let havePrimary = info.isPrimary; + for (const d of this.fakeDisplays) { + if (d.id === id) { + d.isPrimary = info.isPrimary; + } else if (havePrimary) { + d.isPrimary = false; + } else { + d.isPrimary = true; + havePrimary = true; + } } - return undefined; - }, + this.updateLayouts_(); + } + if (info.rotation !== undefined) { + display.rotation = info.rotation; + } + }, - /** @private */ - updateLayouts_() { - this.fakeLayouts = []; - let primaryId = ''; + /** @override */ + getDisplayLayout(callback) { + setTimeout(function() { + // Create a shallow copy to trigger Polymer data binding updates. + callback(this.fakeLayouts.slice()); + this.getLayoutCalled.resolve(); + // Reset the promise resolver. + this.getLayoutCalled = new PromiseResolver(); + }.bind(this)); + }, + + /** @override */ + setDisplayLayout(layouts, callback) { + this.fakeLayouts = layouts; + callback(); + }, + + /** @override */ + setMirrorMode(info, callback) { + let mirroringSourceId = ''; + if (info.mode === chrome.system.display.MirrorMode.NORMAL) { + // Select the primary display as the mirroring source. for (const d of this.fakeDisplays) { if (d.isPrimary) { - primaryId = d.id; + mirroringSourceId = d.id; break; } } - for (const d of this.fakeDisplays) { - this.fakeLayouts.push({ - id: d.id, - parentId: d.isPrimary ? '' : primaryId, - position: chrome.system.display.LayoutPosition.RIGHT, - offset: 0 - }); + } + for (const d of this.fakeDisplays) { + d.mirroringSourceId = mirroringSourceId; + } + callback(); + }, + + /** @override */ + onDisplayChanged: new FakeChromeEvent(), + + /** @private */ + getFakeDisplay_(id) { + const idx = this.fakeDisplays.findIndex(function(display) { + return display.id === id; + }); + if (idx >= 0) { + return this.fakeDisplays[idx]; + } + return undefined; + }, + + /** @private */ + updateLayouts_() { + this.fakeLayouts = []; + let primaryId = ''; + for (const d of this.fakeDisplays) { + if (d.isPrimary) { + primaryId = d.id; + break; } } - }; - - // #cr_define_end - return {FakeSystemDisplay: FakeSystemDisplay}; -}); + for (const d of this.fakeDisplays) { + this.fakeLayouts.push({ + id: d.id, + parentId: d.isPrimary ? '' : primaryId, + position: chrome.system.display.LayoutPosition.RIGHT, + offset: 0 + }); + } + } +};
diff --git a/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js b/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js index de930d6f..8fadfcc 100644 --- a/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js +++ b/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js
@@ -4,776 +4,755 @@ 'use strict'; -// clang-format off -// #import 'chrome://os-settings/chromeos/os_settings.js'; +import {TestKerberosAccountsBrowserProxy, TEST_KERBEROS_ACCOUNTS} from './test_kerberos_accounts_browser_proxy.js'; +import {Router, Route, routes, KerberosErrorType, KerberosConfigErrorCode, KerberosAccountsBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js'; +import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {flushTasks} from 'chrome://test/test_util.js'; +import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; +import {waitAfterNextRender} from 'chrome://test/test_util.js'; -// #import {TestKerberosAccountsBrowserProxy, TEST_KERBEROS_ACCOUNTS} from './test_kerberos_accounts_browser_proxy.m.js'; -// #import {Router, Route, routes, KerberosErrorType, KerberosConfigErrorCode, KerberosAccountsBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js'; -// #import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; -// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -// #import {flushTasks} from 'chrome://test/test_util.js'; -// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; -// #import {waitAfterNextRender} from 'chrome://test/test_util.js'; -// clang-format on +// Tests for the Kerberos Accounts settings page. +suite('KerberosAccountsTests', function() { + let browserProxy = null; + let kerberosAccounts = null; + let accountList = null; -cr.define('settings_kerberos_accounts', function() { - // Tests for the Kerberos Accounts settings page. - suite('KerberosAccountsTests', function() { - let browserProxy = null; - let kerberosAccounts = null; - let accountList = null; + // Account indices (to help readability). + const Account = { + FIRST: 0, + SECOND: 1, + THIRD: 1, + }; - // Account indices (to help readability). - const Account = { - FIRST: 0, - SECOND: 1, - THIRD: 1, - }; + // Indices of 'More Actions' buttons. + const MoreActions = { + REFRESH_NOW: 0, + SET_AS_ACTIVE_ACCOUNT: 1, + REMOVE_ACCOUNT: 2, + }; - // Indices of 'More Actions' buttons. - const MoreActions = { - REFRESH_NOW: 0, - SET_AS_ACTIVE_ACCOUNT: 1, - REMOVE_ACCOUNT: 2, - }; + setup(function() { + routes.BASIC = new Route('/'), + routes.KERBEROS = routes.BASIC.createSection('/kerberos', 'kerberos'); + routes.KERBEROS_ACCOUNTS_V2 = + routes.KERBEROS.createChild('/kerberos/kerberosAccounts'); - setup(function() { - settings.routes.BASIC = new settings.Route('/'), - settings.routes.KERBEROS = - settings.routes.BASIC.createSection('/kerberos', 'kerberos'); - settings.routes.KERBEROS_ACCOUNTS_V2 = - settings.routes.KERBEROS.createChild('/kerberos/kerberosAccounts'); + Router.resetInstanceForTesting(new Router(routes)); - settings.Router.resetInstanceForTesting( - new settings.Router(settings.routes)); + browserProxy = new TestKerberosAccountsBrowserProxy(); + KerberosAccountsBrowserProxyImpl.instance_ = browserProxy; + PolymerTest.clearBody(); + createDialog(); + }); - browserProxy = new TestKerberosAccountsBrowserProxy(); - settings.KerberosAccountsBrowserProxyImpl.instance_ = browserProxy; - PolymerTest.clearBody(); - createDialog(); - }); + teardown(function() { + kerberosAccounts.remove(); + KerberosAccountsBrowserProxyImpl.instance_ = undefined; + }); - teardown(function() { + function createDialog() { + if (kerberosAccounts) { kerberosAccounts.remove(); - settings.KerberosAccountsBrowserProxyImpl.instance_ = undefined; - }); - - function createDialog() { - if (kerberosAccounts) { - kerberosAccounts.remove(); - } - - kerberosAccounts = document.createElement('settings-kerberos-accounts'); - document.body.appendChild(kerberosAccounts); - - accountList = kerberosAccounts.$$('#account-list'); - assertTrue(!!accountList); } - function clickMoreActions(accountIndex, moreActionsIndex) { - // Click 'More actions' for the given account. - kerberosAccounts.shadowRoot - .querySelectorAll('.more-actions')[accountIndex] - .click(); - // Click on the given action. - kerberosAccounts.$$('cr-action-menu') - .querySelectorAll('button')[moreActionsIndex] - .click(); - } + kerberosAccounts = document.createElement('settings-kerberos-accounts'); + document.body.appendChild(kerberosAccounts); - // Can be used to wait for event |eventName| on |element|, e.g. - // await onEvent(addDialog, 'close'); - function onEvent(element, eventName) { - return new Promise(function(resolve) { - element.addEventListener(eventName, function callback() { - element.removeEventListener(eventName, callback); - resolve(); - }); + accountList = kerberosAccounts.$$('#account-list'); + assertTrue(!!accountList); + } + + function clickMoreActions(accountIndex, moreActionsIndex) { + // Click 'More actions' for the given account. + kerberosAccounts.shadowRoot.querySelectorAll('.more-actions')[accountIndex] + .click(); + // Click on the given action. + kerberosAccounts.$$('cr-action-menu') + .querySelectorAll('button')[moreActionsIndex] + .click(); + } + + // Can be used to wait for event |eventName| on |element|, e.g. + // await onEvent(addDialog, 'close'); + function onEvent(element, eventName) { + return new Promise(function(resolve) { + element.addEventListener(eventName, function callback() { + element.removeEventListener(eventName, callback); + resolve(); }); - } - - test('AccountListIsPopulatedAtStartup', async () => { - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - // The test accounts were added in |getAccounts()| mock above. - assertEquals(TEST_KERBEROS_ACCOUNTS.length, accountList.items.length); }); + } - test('AccountListSignedInSignedOutLabels', async () => { - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - accountList = - kerberosAccounts.shadowRoot.querySelectorAll('.account-list-item'); - assertEquals(TEST_KERBEROS_ACCOUNTS.length, accountList.length); - - // Show 'Valid for <duration>' for accounts that are signed in. - let signedIn = accountList[0].querySelector('.signed-in'); - let signedOut = accountList[0].querySelector('.signed-out'); - assertTrue(TEST_KERBEROS_ACCOUNTS[0].isSignedIn); - assertFalse(signedIn.hidden); - assertTrue(signedOut.hidden); - assertEquals( - 'Valid for ' + TEST_KERBEROS_ACCOUNTS[0].validForDuration, - signedIn.innerText); - - // Show 'Expired' for accounts that are not signed in. - signedIn = accountList[1].querySelector('.signed-in'); - signedOut = accountList[1].querySelector('.signed-out'); - assertFalse(TEST_KERBEROS_ACCOUNTS[1].isSignedIn); - assertTrue(signedIn.hidden); - assertFalse(signedOut.hidden); - assertEquals('Expired', signedOut.innerText); - }); - - test('AddAccount', function() { - // The kerberos-add-account-dialog shouldn't be open yet. - assertTrue(!kerberosAccounts.$$('kerberos-add-account-dialog')); - - kerberosAccounts.$$('#add-account-button').click(); - Polymer.dom.flush(); - - const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); - assertTrue(!!addDialog); - assertEquals('', addDialog.$.username.value); - }); - - test('ReauthenticateAccount', async () => { - // Wait until accounts are loaded. - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - - // The kerberos-add-account-dialog shouldn't be open yet. - assertTrue(!kerberosAccounts.$$('kerberos-add-account-dialog')); - - // Click "Sign-In" on an existing account. - // Note that both accounts have a reauth button, but the first one is - // hidden, so click the second one (clicking a hidden button works, but - // it feels weird). - kerberosAccounts.shadowRoot - .querySelectorAll('.reauth-button')[Account.SECOND] - .click(); - Polymer.dom.flush(); - - // Now the kerberos-add-account-dialog should be open with preset - // username. - const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); - assertTrue(!!addDialog); - assertEquals( - TEST_KERBEROS_ACCOUNTS[Account.SECOND].principalName, - addDialog.$.username.value); - }); - - // Appending '?kerberos_reauth=<principal>' to the URL opens the reauth - // dialog for that account. - test('HandleReauthQueryParameter', async () => { - const principal_name = - TEST_KERBEROS_ACCOUNTS[Account.FIRST].principalName; - const params = new URLSearchParams(); - params.append('kerberos_reauth', principal_name); - settings.Router.getInstance().navigateTo( - settings.routes.KERBEROS_ACCOUNTS_V2, params); - - // The flushTasks is necessary since the kerberos_reauth param would - // otherwise be handled AFTER the callback below is executed. - await browserProxy.whenCalled('getAccounts'); - await test_util.flushTasks(); - Polymer.dom.flush(); - const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); - assertTrue(!!addDialog); - assertEquals(principal_name, addDialog.$.username.value); - }); - - test('RefreshNow', async () => { - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - clickMoreActions(Account.FIRST, MoreActions.REFRESH_NOW); - Polymer.dom.flush(); - - const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); - assertTrue(!!addDialog); - assertEquals( - TEST_KERBEROS_ACCOUNTS[Account.FIRST].principalName, - addDialog.$.username.value); - }); - - test('RefreshAccountShowsToast', async () => { - const toast = kerberosAccounts.$$('#account-toast'); - assertTrue(!!toast); - assertFalse(toast.open); - - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - clickMoreActions(Account.FIRST, MoreActions.REFRESH_NOW); - Polymer.dom.flush(); - - const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); - assertTrue(!!addDialog); - addDialog.$$('.action-button').click(); - Polymer.dom.flush(); - - await onEvent(addDialog, 'close'); - await test_util.flushTasks(); - Polymer.dom.flush(); - assertTrue(toast.open); - assertTrue(kerberosAccounts.$$('#account-toast-label') - .innerHTML.includes('refreshed')); - }); - - test('RemoveAccount', async () => { - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - clickMoreActions(Account.FIRST, MoreActions.REMOVE_ACCOUNT); - const account = await browserProxy.whenCalled('removeAccount'); - assertEquals( - TEST_KERBEROS_ACCOUNTS[Account.FIRST].principalName, - account.principalName); - }); - - test('Deep link to remove account dropdown', async () => { - const params = new URLSearchParams(); - params.append('settingId', '1801'); - settings.Router.getInstance().navigateTo( - settings.routes.KERBEROS_ACCOUNTS_V2, params); - - await browserProxy.whenCalled('getAccounts'); - await test_util.flushTasks(); - Polymer.dom.flush(); - - const deepLinkElement = - kerberosAccounts.root.querySelectorAll('cr-icon-button')[0]; - assertTrue(!!deepLinkElement); - await test_util.waitAfterNextRender(deepLinkElement); - assertEquals( - deepLinkElement, getDeepActiveElement(), - 'Kebab menu should be focused for settingId=1801.'); - }); - - test('RemoveAccountShowsToast', async () => { - const toast = kerberosAccounts.$$('#account-toast'); - assertTrue(!!toast); - assertFalse(toast.open); - - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - clickMoreActions(Account.FIRST, MoreActions.REMOVE_ACCOUNT); - await browserProxy.whenCalled('removeAccount'); - await test_util.flushTasks(); - Polymer.dom.flush(); - assertTrue(toast.open); - assertTrue(kerberosAccounts.$$('#account-toast-label') - .innerHTML.includes('removed')); - }); - - test('AccountListIsUpdatedWhenKerberosAccountsUpdates', function() { - assertEquals(1, browserProxy.getCallCount('getAccounts')); - cr.webUIListenerCallback('kerberos-accounts-changed'); - assertEquals(2, browserProxy.getCallCount('getAccounts')); - }); - - test('SetAsActiveAccount', async () => { - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - clickMoreActions(Account.SECOND, MoreActions.SET_AS_ACTIVE_ACCOUNT); - const account = await browserProxy.whenCalled('setAsActiveAccount'); - assertEquals( - TEST_KERBEROS_ACCOUNTS[Account.SECOND].principalName, - account.principalName); - }); - - test('ShowPolicyIndicatorForManagedAccounts', async () => { - // Make sure we have at least one managed and one unmanaged account. - assertFalse(TEST_KERBEROS_ACCOUNTS[0].isManaged); - assertTrue(TEST_KERBEROS_ACCOUNTS[2].isManaged); - - await browserProxy.whenCalled('getAccounts'); - Polymer.dom.flush(); - accountList = - kerberosAccounts.shadowRoot.querySelectorAll('.account-list-item'); - assertEquals(TEST_KERBEROS_ACCOUNTS.length, accountList.length); - - for (let i = 0; i < TEST_KERBEROS_ACCOUNTS.length; i++) { - // Assert account has policy indicator iff account is managed. - const hasAccountPolicyIndicator = - !!accountList[i].querySelector('.account-policy-indicator'); - assertEquals( - TEST_KERBEROS_ACCOUNTS[i].isManaged, hasAccountPolicyIndicator); - - // Assert 'Remove' button is disabled iff account is managed. - accountList[i].querySelector('.more-actions').click(); - const moreActions = - kerberosAccounts.$$('cr-action-menu').querySelectorAll('button'); - const removeAccountButton = moreActions[MoreActions.REMOVE_ACCOUNT]; - assertEquals( - TEST_KERBEROS_ACCOUNTS[i].isManaged, removeAccountButton.disabled); - - // Assert 'Remove' button has policy indicator iff account is managed. - Polymer.dom.flush(); - const hasRemovalPolicyIndicator = !!removeAccountButton.querySelector( - '#remove-account-policy-indicator'); - assertEquals( - TEST_KERBEROS_ACCOUNTS[i].isManaged, hasRemovalPolicyIndicator); - - kerberosAccounts.$$('cr-action-menu').close(); - } - }); - - test('AddAccountsAllowed', function() { - assertTrue(loadTimeData.getBoolean('kerberosAddAccountsAllowed')); - createDialog(); - assertTrue(!kerberosAccounts.$$('#add-account-policy-indicator')); - assertFalse(kerberosAccounts.$$('#add-account-button').disabled); - }); - - test('AddAccountsNotAllowed', function() { - loadTimeData.overrideValues({kerberosAddAccountsAllowed: false}); - createDialog(); - Polymer.dom.flush(); - assertTrue(!!kerberosAccounts.$$('#add-account-policy-indicator')); - assertTrue(kerberosAccounts.$$('#add-account-button').disabled); - - // Reset for further tests. - loadTimeData.overrideValues({kerberosAddAccountsAllowed: true}); - }); + test('AccountListIsPopulatedAtStartup', async () => { + await browserProxy.whenCalled('getAccounts'); + flush(); + // The test accounts were added in |getAccounts()| mock above. + assertEquals(TEST_KERBEROS_ACCOUNTS.length, accountList.items.length); }); - // Tests for the kerberos-add-account-dialog element. - suite('KerberosAddAccountTests', function() { - let browserProxy = null; + test('AccountListSignedInSignedOutLabels', async () => { + await browserProxy.whenCalled('getAccounts'); + flush(); + accountList = + kerberosAccounts.shadowRoot.querySelectorAll('.account-list-item'); + assertEquals(TEST_KERBEROS_ACCOUNTS.length, accountList.length); - let dialog = null; - let addDialog = null; + // Show 'Valid for <duration>' for accounts that are signed in. + let signedIn = accountList[0].querySelector('.signed-in'); + let signedOut = accountList[0].querySelector('.signed-out'); + assertTrue(TEST_KERBEROS_ACCOUNTS[0].isSignedIn); + assertFalse(signedIn.hidden); + assertTrue(signedOut.hidden); + assertEquals( + 'Valid for ' + TEST_KERBEROS_ACCOUNTS[0].validForDuration, + signedIn.innerText); - let username = null; - let password = null; - let rememberPassword = null; - let advancedConfigButton = null; - let actionButton = null; - let generalError = null; - let title = null; + // Show 'Expired' for accounts that are not signed in. + signedIn = accountList[1].querySelector('.signed-in'); + signedOut = accountList[1].querySelector('.signed-out'); + assertFalse(TEST_KERBEROS_ACCOUNTS[1].isSignedIn); + assertTrue(signedIn.hidden); + assertFalse(signedOut.hidden); + assertEquals('Expired', signedOut.innerText); + }); - // Indices of 'addAccount' params. - const AddParams = { - PRINCIPAL_NAME: 0, - PASSWORD: 1, - REMEMBER_PASSWORD: 2, - CONFIG: 3, - ALLOW_EXISTING: 4, + test('AddAccount', function() { + // The kerberos-add-account-dialog shouldn't be open yet. + assertTrue(!kerberosAccounts.$$('kerberos-add-account-dialog')); + + kerberosAccounts.$$('#add-account-button').click(); + flush(); + + const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); + assertTrue(!!addDialog); + assertEquals('', addDialog.$.username.value); + }); + + test('ReauthenticateAccount', async () => { + // Wait until accounts are loaded. + await browserProxy.whenCalled('getAccounts'); + flush(); + + // The kerberos-add-account-dialog shouldn't be open yet. + assertTrue(!kerberosAccounts.$$('kerberos-add-account-dialog')); + + // Click "Sign-In" on an existing account. + // Note that both accounts have a reauth button, but the first one is + // hidden, so click the second one (clicking a hidden button works, but + // it feels weird). + kerberosAccounts.shadowRoot + .querySelectorAll('.reauth-button')[Account.SECOND] + .click(); + flush(); + + // Now the kerberos-add-account-dialog should be open with preset + // username. + const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); + assertTrue(!!addDialog); + assertEquals( + TEST_KERBEROS_ACCOUNTS[Account.SECOND].principalName, + addDialog.$.username.value); + }); + + // Appending '?kerberos_reauth=<principal>' to the URL opens the reauth + // dialog for that account. + test('HandleReauthQueryParameter', async () => { + const principal_name = TEST_KERBEROS_ACCOUNTS[Account.FIRST].principalName; + const params = new URLSearchParams(); + params.append('kerberos_reauth', principal_name); + Router.getInstance().navigateTo(routes.KERBEROS_ACCOUNTS_V2, params); + + // The flushTasks is necessary since the kerberos_reauth param would + // otherwise be handled AFTER the callback below is executed. + await browserProxy.whenCalled('getAccounts'); + await flushTasks(); + flush(); + const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); + assertTrue(!!addDialog); + assertEquals(principal_name, addDialog.$.username.value); + }); + + test('RefreshNow', async () => { + await browserProxy.whenCalled('getAccounts'); + flush(); + clickMoreActions(Account.FIRST, MoreActions.REFRESH_NOW); + flush(); + + const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); + assertTrue(!!addDialog); + assertEquals( + TEST_KERBEROS_ACCOUNTS[Account.FIRST].principalName, + addDialog.$.username.value); + }); + + test('RefreshAccountShowsToast', async () => { + const toast = kerberosAccounts.$$('#account-toast'); + assertTrue(!!toast); + assertFalse(toast.open); + + await browserProxy.whenCalled('getAccounts'); + flush(); + clickMoreActions(Account.FIRST, MoreActions.REFRESH_NOW); + flush(); + + const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog'); + assertTrue(!!addDialog); + addDialog.$$('.action-button').click(); + flush(); + + await onEvent(addDialog, 'close'); + await flushTasks(); + flush(); + assertTrue(toast.open); + assertTrue(kerberosAccounts.$$('#account-toast-label') + .innerHTML.includes('refreshed')); + }); + + test('RemoveAccount', async () => { + await browserProxy.whenCalled('getAccounts'); + flush(); + clickMoreActions(Account.FIRST, MoreActions.REMOVE_ACCOUNT); + const account = await browserProxy.whenCalled('removeAccount'); + assertEquals( + TEST_KERBEROS_ACCOUNTS[Account.FIRST].principalName, + account.principalName); + }); + + test('Deep link to remove account dropdown', async () => { + const params = new URLSearchParams(); + params.append('settingId', '1801'); + Router.getInstance().navigateTo(routes.KERBEROS_ACCOUNTS_V2, params); + + await browserProxy.whenCalled('getAccounts'); + await flushTasks(); + flush(); + + const deepLinkElement = + kerberosAccounts.root.querySelectorAll('cr-icon-button')[0]; + assertTrue(!!deepLinkElement); + await waitAfterNextRender(deepLinkElement); + assertEquals( + deepLinkElement, getDeepActiveElement(), + 'Kebab menu should be focused for settingId=1801.'); + }); + + test('RemoveAccountShowsToast', async () => { + const toast = kerberosAccounts.$$('#account-toast'); + assertTrue(!!toast); + assertFalse(toast.open); + + await browserProxy.whenCalled('getAccounts'); + flush(); + clickMoreActions(Account.FIRST, MoreActions.REMOVE_ACCOUNT); + await browserProxy.whenCalled('removeAccount'); + await flushTasks(); + flush(); + assertTrue(toast.open); + assertTrue(kerberosAccounts.$$('#account-toast-label') + .innerHTML.includes('removed')); + }); + + test('AccountListIsUpdatedWhenKerberosAccountsUpdates', function() { + assertEquals(1, browserProxy.getCallCount('getAccounts')); + cr.webUIListenerCallback('kerberos-accounts-changed'); + assertEquals(2, browserProxy.getCallCount('getAccounts')); + }); + + test('SetAsActiveAccount', async () => { + await browserProxy.whenCalled('getAccounts'); + flush(); + clickMoreActions(Account.SECOND, MoreActions.SET_AS_ACTIVE_ACCOUNT); + const account = await browserProxy.whenCalled('setAsActiveAccount'); + assertEquals( + TEST_KERBEROS_ACCOUNTS[Account.SECOND].principalName, + account.principalName); + }); + + test('ShowPolicyIndicatorForManagedAccounts', async () => { + // Make sure we have at least one managed and one unmanaged account. + assertFalse(TEST_KERBEROS_ACCOUNTS[0].isManaged); + assertTrue(TEST_KERBEROS_ACCOUNTS[2].isManaged); + + await browserProxy.whenCalled('getAccounts'); + flush(); + accountList = + kerberosAccounts.shadowRoot.querySelectorAll('.account-list-item'); + assertEquals(TEST_KERBEROS_ACCOUNTS.length, accountList.length); + + for (let i = 0; i < TEST_KERBEROS_ACCOUNTS.length; i++) { + // Assert account has policy indicator iff account is managed. + const hasAccountPolicyIndicator = + !!accountList[i].querySelector('.account-policy-indicator'); + assertEquals( + TEST_KERBEROS_ACCOUNTS[i].isManaged, hasAccountPolicyIndicator); + + // Assert 'Remove' button is disabled iff account is managed. + accountList[i].querySelector('.more-actions').click(); + const moreActions = + kerberosAccounts.$$('cr-action-menu').querySelectorAll('button'); + const removeAccountButton = moreActions[MoreActions.REMOVE_ACCOUNT]; + assertEquals( + TEST_KERBEROS_ACCOUNTS[i].isManaged, removeAccountButton.disabled); + + // Assert 'Remove' button has policy indicator iff account is managed. + flush(); + const hasRemovalPolicyIndicator = !!removeAccountButton.querySelector( + '#remove-account-policy-indicator'); + assertEquals( + TEST_KERBEROS_ACCOUNTS[i].isManaged, hasRemovalPolicyIndicator); + + kerberosAccounts.$$('cr-action-menu').close(); + } + }); + + test('AddAccountsAllowed', function() { + assertTrue(loadTimeData.getBoolean('kerberosAddAccountsAllowed')); + createDialog(); + assertTrue(!kerberosAccounts.$$('#add-account-policy-indicator')); + assertFalse(kerberosAccounts.$$('#add-account-button').disabled); + }); + + test('AddAccountsNotAllowed', function() { + loadTimeData.overrideValues({kerberosAddAccountsAllowed: false}); + createDialog(); + flush(); + assertTrue(!!kerberosAccounts.$$('#add-account-policy-indicator')); + assertTrue(kerberosAccounts.$$('#add-account-button').disabled); + + // Reset for further tests. + loadTimeData.overrideValues({kerberosAddAccountsAllowed: true}); + }); +}); + +// Tests for the kerberos-add-account-dialog element. +suite('KerberosAddAccountTests', function() { + let browserProxy = null; + + let dialog = null; + let addDialog = null; + + let username = null; + let password = null; + let rememberPassword = null; + let advancedConfigButton = null; + let actionButton = null; + let generalError = null; + let title = null; + + // Indices of 'addAccount' params. + const AddParams = { + PRINCIPAL_NAME: 0, + PASSWORD: 1, + REMEMBER_PASSWORD: 2, + CONFIG: 3, + ALLOW_EXISTING: 4, + }; + + setup(function() { + browserProxy = new TestKerberosAccountsBrowserProxy(); + KerberosAccountsBrowserProxyImpl.instance_ = browserProxy; + PolymerTest.clearBody(); + createDialog(null); + }); + + teardown(function() { + dialog.remove(); + KerberosAccountsBrowserProxyImpl.instance_ = undefined; + }); + + function createDialog(presetAccount) { + if (dialog) { + dialog.remove(); + } + + dialog = document.createElement('kerberos-add-account-dialog'); + dialog.presetAccount = presetAccount; + document.body.appendChild(dialog); + + addDialog = dialog.$.addDialog; + assertTrue(!!addDialog); + + username = dialog.$.username; + assertTrue(!!username); + + password = dialog.$.password; + assertTrue(!!password); + + rememberPassword = dialog.$.rememberPassword; + assertTrue(!!rememberPassword); + + advancedConfigButton = dialog.$.advancedConfigButton; + assertTrue(!!advancedConfigButton); + + actionButton = addDialog.querySelector('.action-button'); + assertTrue(!!actionButton); + + generalError = dialog.$['general-error-message']; + assertTrue(!!generalError); + + title = dialog.$$('[slot=title]').innerText; + assertTrue(!!title); + } + + // Sets |error| as error result for addAccount(), simulates a click on the + // addAccount button and checks that |errorElement| has an non-empty + // innerText value afterwards. + async function checkAddAccountError(error, errorElement) { + flush(); + assertEquals(0, errorElement.innerText.length); + browserProxy.addAccountError = error; + actionButton.click(); + await browserProxy.whenCalled('addAccount'); + flush(); + assertNotEquals(0, errorElement.innerText.length); + } + + // Opens the Advanced Config dialog, sets |config| as Kerberos configuration + // and clicks 'Save'. Returns a promise with the validation result. + function setConfig(config) { + advancedConfigButton.click(); + flush(); + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + const configElement = advancedConfigDialog.querySelector('#config'); + assertFalse(configElement.disabled); + configElement.value = config; + advancedConfigDialog.querySelector('.action-button').click(); + flush(); + return browserProxy.whenCalled('validateConfig'); + } + + // Opens the Advanced Config dialog, asserts that |config| is set as + // Kerberos configuration and clicks 'Cancel'. + function assertConfig(config) { + advancedConfigButton.click(); + flush(); + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + assertEquals(config, advancedConfigDialog.querySelector('#config').value); + advancedConfigDialog.querySelector('.cancel-button').click(); + flush(); + } + + // Verifies expected states if no account is preset. + test('StatesWithoutPresetAccount', function() { + assertTrue(title.startsWith('Add')); + assertEquals('Add', actionButton.innerText); + assertFalse(username.disabled); + assertEquals('', username.value); + assertEquals('', password.value); + assertConfig(loadTimeData.getString('defaultKerberosConfig')); + assertFalse(rememberPassword.checked); + }); + + // Verifies expected states if an account is preset. + test('StatesWithPresetAccount', function() { + createDialog(TEST_KERBEROS_ACCOUNTS[0]); + assertTrue(title.startsWith('Refresh')); + assertEquals('Refresh', actionButton.innerText); + assertTrue(username.readonly); + assertEquals(TEST_KERBEROS_ACCOUNTS[0].principalName, username.value); + assertConfig(TEST_KERBEROS_ACCOUNTS[0].config); + // Password and remember password are tested below since the contents + // depends on the passwordWasRemembered property of the account. + }); + + // The password input field is empty and 'Remember password' is not preset + // if |passwordWasRemembered| is false. + test('PasswordNotPresetIfPasswordWasNotRemembered', function() { + assertFalse(TEST_KERBEROS_ACCOUNTS[0].passwordWasRemembered); + createDialog(TEST_KERBEROS_ACCOUNTS[0]); + assertEquals('', password.value); + assertFalse(rememberPassword.checked); + }); + + // The password input field is not empty and 'Remember password' is preset + // if |passwordWasRemembered| is true. + test('PasswordPresetIfPasswordWasRemembered', function() { + assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); + createDialog(TEST_KERBEROS_ACCOUNTS[1]); + assertNotEquals('', password.value); + assertTrue(rememberPassword.checked); + }); + + test('RememberPasswordEnabled', function() { + assertTrue(loadTimeData.getBoolean('kerberosRememberPasswordEnabled')); + assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); + createDialog(TEST_KERBEROS_ACCOUNTS[1]); + + assertTrue(!dialog.$$('#rememberPasswordPolicyIndicator')); + assertFalse(rememberPassword.disabled); + assertTrue(rememberPassword.checked); + assertNotEquals('', password.value); + }); + + test('RememberPasswordDisabled', function() { + loadTimeData.overrideValues({kerberosRememberPasswordEnabled: false}); + assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); + createDialog(TEST_KERBEROS_ACCOUNTS[1]); + flush(); + + assertTrue(!!dialog.$$('#rememberPasswordPolicyIndicator')); + assertTrue(rememberPassword.disabled); + assertFalse(rememberPassword.checked); + assertEquals('', password.value); + + // Reset for further tests. + loadTimeData.overrideValues({kerberosRememberPasswordEnabled: true}); + }); + + test('RememberPasswordVisibleOnUserSessions', function() { + assertFalse(loadTimeData.getBoolean('isGuest')); + createDialog(null); + flush(); + + assertFalse(dialog.$$('#rememberPasswordContainer').hidden); + }); + + test('RememberPasswordHiddenOnMgs', function() { + loadTimeData.overrideValues({isGuest: true}); + createDialog(null); + flush(); + + assertTrue(dialog.$$('#rememberPasswordContainer').hidden); + + // Reset for further tests. + loadTimeData.overrideValues({isGuest: false}); + }); + + // By clicking the action button, all field values are passed to the + // 'addAccount' browser proxy method. + test('ActionButtonPassesFieldValues', async () => { + const EXPECTED_USER = 'testuser'; + const EXPECTED_PASS = 'testpass'; + const EXPECTED_REMEMBER_PASS = true; + const EXPECTED_CONFIG = 'testconf'; + + username.value = EXPECTED_USER; + password.value = EXPECTED_PASS; + const result = await setConfig(EXPECTED_CONFIG); + rememberPassword.checked = EXPECTED_REMEMBER_PASS; + + assertFalse(actionButton.disabled); + actionButton.click(); + const args = await browserProxy.whenCalled('addAccount'); + assertEquals(EXPECTED_USER, args[AddParams.PRINCIPAL_NAME]); + assertEquals(EXPECTED_PASS, args[AddParams.PASSWORD]); + assertEquals(EXPECTED_REMEMBER_PASS, args[AddParams.REMEMBER_PASSWORD]); + assertEquals(EXPECTED_CONFIG, args[AddParams.CONFIG]); + + // Should be false if a new account is added. See also + // AllowExistingIsTrueForPresetAccounts test. + assertFalse(args[AddParams.ALLOW_EXISTING]); + }); + + // If an account is preset, overwriting that account should be allowed. + test('AllowExistingIsTrueForPresetAccounts', async () => { + // Populate dialog with preset account. + createDialog(TEST_KERBEROS_ACCOUNTS[1]); + actionButton.click(); + const args = await browserProxy.whenCalled('addAccount'); + assertTrue(args[AddParams.ALLOW_EXISTING]); + }); + + // While an account is being added, the action button is disabled. + test('ActionButtonDisableWhileInProgress', async () => { + assertFalse(actionButton.disabled); + actionButton.click(); + assertTrue(actionButton.disabled); + await browserProxy.whenCalled('addAccount'); + assertFalse(actionButton.disabled); + }); + + // If the account has passwordWasRemembered === true and the user just + // clicks the 'Add' button, an empty password is submitted. + test('SubmitsEmptyPasswordIfRememberedPasswordIsUsed', async () => { + assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); + createDialog(TEST_KERBEROS_ACCOUNTS[1]); + actionButton.click(); + const args = await browserProxy.whenCalled('addAccount'); + assertEquals('', args[AddParams.PASSWORD]); + assertTrue(args[AddParams.REMEMBER_PASSWORD]); + }); + + // If the account has passwordWasRemembered === true and the user changes + // the password before clicking the action button, the changed password is + // submitted. + test('SubmitsChangedPasswordIfRememberedPasswordIsChanged', async () => { + assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); + createDialog(TEST_KERBEROS_ACCOUNTS[1]); + password.inputElement.value = 'some edit'; + password.dispatchEvent(new CustomEvent('input')); + actionButton.click(); + const args = await browserProxy.whenCalled('addAccount'); + assertNotEquals('', args[AddParams.PASSWORD]); + assertTrue(args[AddParams.REMEMBER_PASSWORD]); + }); + + test('AdvancedConfigOpenClose', async () => { + assertTrue(!dialog.$$('#advancedConfigDialog')); + assertFalse(addDialog.hidden); + advancedConfigButton.click(); + flush(); + + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + assertTrue(!!advancedConfigDialog); + assertTrue(advancedConfigDialog.open); + assertTrue(addDialog.hidden); + const saveButton = advancedConfigDialog.querySelector('.action-button'); + assertFalse(saveButton.disabled); + saveButton.click(); + flush(); + assertTrue(saveButton.disabled); + + await browserProxy.whenCalled('validateConfig'); + flush(); + assertFalse(saveButton.disabled); + assertTrue(!dialog.$$('#advancedConfigDialog')); + assertFalse(addDialog.hidden); + assertTrue(addDialog.open); + }); + + test('AdvancedConfigurationSaveKeepsConfig', async () => { + advancedConfigButton.click(); + flush(); + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + assertTrue(!!advancedConfigDialog); + + // Change config and save. + const modifiedConfig = 'modified'; + advancedConfigDialog.querySelector('#config').value = modifiedConfig; + advancedConfigDialog.querySelector('.action-button').click(); + + // Changed value should stick. + await browserProxy.whenCalled('validateConfig'); + flush(); + assertConfig(modifiedConfig); + }); + + test('AdvancedConfigurationCancelResetsConfig', function() { + advancedConfigButton.click(); + flush(); + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + assertTrue(!!advancedConfigDialog); + + // Change config and cancel. + const prevConfig = advancedConfigDialog.querySelector('#config').value; + advancedConfigDialog.querySelector('#config').value = 'modified'; + advancedConfigDialog.querySelector('.cancel-button').click(); + flush(); + + // Changed value should NOT stick. + assertConfig(prevConfig); + }); + + test('AdvancedConfigurationDisabledByPolicy', function() { + assertTrue(TEST_KERBEROS_ACCOUNTS[2].isManaged); + createDialog(TEST_KERBEROS_ACCOUNTS[2]); + advancedConfigButton.click(); + flush(); + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + assertTrue(!!advancedConfigDialog); + assertTrue( + !!advancedConfigDialog.querySelector('#advancedConfigPolicyIndicator')); + assertTrue(advancedConfigDialog.querySelector('#config').disabled); + }); + + test('AdvancedConfigurationValidationError', async () => { + advancedConfigButton.click(); + flush(); + const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); + assertTrue(!!advancedConfigDialog); + + // Cause a validation error. + browserProxy.validateConfigResult = { + error: KerberosErrorType.kBadConfig, + errorInfo: {code: KerberosConfigErrorCode.kKeyNotSupported, lineIndex: 0} }; - setup(function() { - browserProxy = new TestKerberosAccountsBrowserProxy(); - settings.KerberosAccountsBrowserProxyImpl.instance_ = browserProxy; - PolymerTest.clearBody(); - createDialog(null); - }); + // Clicking the action button (aka 'Save') validates the config. + advancedConfigDialog.querySelector('.action-button').click(); - teardown(function() { - dialog.remove(); - settings.KerberosAccountsBrowserProxyImpl.instance_ = undefined; - }); + await browserProxy.whenCalled('validateConfig'); - function createDialog(presetAccount) { - if (dialog) { - dialog.remove(); - } + // Wait for dialog to process the 'validateConfig' result (sets error + // message etc.). + await flushTasks(); - dialog = document.createElement('kerberos-add-account-dialog'); - dialog.presetAccount = presetAccount; - document.body.appendChild(dialog); + // Is some error text set? + const configError = + advancedConfigDialog.querySelector('#config-error-message'); + assertTrue(!!configError); + assertNotEquals(0, configError.innerText.length); - addDialog = dialog.$.addDialog; - assertTrue(!!addDialog); + // Is something selected? + const configElement = advancedConfigDialog.querySelector('#config'); + const textArea = configElement.$.input; + assertEquals(0, textArea.selectionStart); + assertNotEquals(0, textArea.selectionEnd); - username = dialog.$.username; - assertTrue(!!username); + // Is the config dialog is still open? + assertTrue(advancedConfigDialog.open); + assertTrue(addDialog.hidden); - password = dialog.$.password; - assertTrue(!!password); - - rememberPassword = dialog.$.rememberPassword; - assertTrue(!!rememberPassword); - - advancedConfigButton = dialog.$.advancedConfigButton; - assertTrue(!!advancedConfigButton); - - actionButton = addDialog.querySelector('.action-button'); - assertTrue(!!actionButton); - - generalError = dialog.$['general-error-message']; - assertTrue(!!generalError); - - title = dialog.$$('[slot=title]').innerText; - assertTrue(!!title); - } - - // Sets |error| as error result for addAccount(), simulates a click on the - // addAccount button and checks that |errorElement| has an non-empty - // innerText value afterwards. - async function checkAddAccountError(error, errorElement) { - Polymer.dom.flush(); - assertEquals(0, errorElement.innerText.length); - browserProxy.addAccountError = error; - actionButton.click(); - await browserProxy.whenCalled('addAccount'); - Polymer.dom.flush(); - assertNotEquals(0, errorElement.innerText.length); - } - - // Opens the Advanced Config dialog, sets |config| as Kerberos configuration - // and clicks 'Save'. Returns a promise with the validation result. - function setConfig(config) { - advancedConfigButton.click(); - Polymer.dom.flush(); - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - const configElement = advancedConfigDialog.querySelector('#config'); - assertFalse(configElement.disabled); - configElement.value = config; - advancedConfigDialog.querySelector('.action-button').click(); - Polymer.dom.flush(); - return browserProxy.whenCalled('validateConfig'); - } - - // Opens the Advanced Config dialog, asserts that |config| is set as - // Kerberos configuration and clicks 'Cancel'. - function assertConfig(config) { - advancedConfigButton.click(); - Polymer.dom.flush(); - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - assertEquals(config, advancedConfigDialog.querySelector('#config').value); - advancedConfigDialog.querySelector('.cancel-button').click(); - Polymer.dom.flush(); - } - - // Verifies expected states if no account is preset. - test('StatesWithoutPresetAccount', function() { - assertTrue(title.startsWith('Add')); - assertEquals('Add', actionButton.innerText); - assertFalse(username.disabled); - assertEquals('', username.value); - assertEquals('', password.value); - assertConfig(loadTimeData.getString('defaultKerberosConfig')); - assertFalse(rememberPassword.checked); - }); - - // Verifies expected states if an account is preset. - test('StatesWithPresetAccount', function() { - createDialog(TEST_KERBEROS_ACCOUNTS[0]); - assertTrue(title.startsWith('Refresh')); - assertEquals('Refresh', actionButton.innerText); - assertTrue(username.readonly); - assertEquals(TEST_KERBEROS_ACCOUNTS[0].principalName, username.value); - assertConfig(TEST_KERBEROS_ACCOUNTS[0].config); - // Password and remember password are tested below since the contents - // depends on the passwordWasRemembered property of the account. - }); - - // The password input field is empty and 'Remember password' is not preset - // if |passwordWasRemembered| is false. - test('PasswordNotPresetIfPasswordWasNotRemembered', function() { - assertFalse(TEST_KERBEROS_ACCOUNTS[0].passwordWasRemembered); - createDialog(TEST_KERBEROS_ACCOUNTS[0]); - assertEquals('', password.value); - assertFalse(rememberPassword.checked); - }); - - // The password input field is not empty and 'Remember password' is preset - // if |passwordWasRemembered| is true. - test('PasswordPresetIfPasswordWasRemembered', function() { - assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); - createDialog(TEST_KERBEROS_ACCOUNTS[1]); - assertNotEquals('', password.value); - assertTrue(rememberPassword.checked); - }); - - test('RememberPasswordEnabled', function() { - assertTrue(loadTimeData.getBoolean('kerberosRememberPasswordEnabled')); - assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); - createDialog(TEST_KERBEROS_ACCOUNTS[1]); - - assertTrue(!dialog.$$('#rememberPasswordPolicyIndicator')); - assertFalse(rememberPassword.disabled); - assertTrue(rememberPassword.checked); - assertNotEquals('', password.value); - }); - - test('RememberPasswordDisabled', function() { - loadTimeData.overrideValues({kerberosRememberPasswordEnabled: false}); - assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); - createDialog(TEST_KERBEROS_ACCOUNTS[1]); - Polymer.dom.flush(); - - assertTrue(!!dialog.$$('#rememberPasswordPolicyIndicator')); - assertTrue(rememberPassword.disabled); - assertFalse(rememberPassword.checked); - assertEquals('', password.value); - - // Reset for further tests. - loadTimeData.overrideValues({kerberosRememberPasswordEnabled: true}); - }); - - test('RememberPasswordVisibleOnUserSessions', function() { - assertFalse(loadTimeData.getBoolean('isGuest')); - createDialog(null); - Polymer.dom.flush(); - - assertFalse(dialog.$$('#rememberPasswordContainer').hidden); - }); - - test('RememberPasswordHiddenOnMgs', function() { - loadTimeData.overrideValues({isGuest: true}); - createDialog(null); - Polymer.dom.flush(); - - assertTrue(dialog.$$('#rememberPasswordContainer').hidden); - - // Reset for further tests. - loadTimeData.overrideValues({isGuest: false}); - }); - - // By clicking the action button, all field values are passed to the - // 'addAccount' browser proxy method. - test('ActionButtonPassesFieldValues', async () => { - const EXPECTED_USER = 'testuser'; - const EXPECTED_PASS = 'testpass'; - const EXPECTED_REMEMBER_PASS = true; - const EXPECTED_CONFIG = 'testconf'; - - username.value = EXPECTED_USER; - password.value = EXPECTED_PASS; - const result = await setConfig(EXPECTED_CONFIG); - rememberPassword.checked = EXPECTED_REMEMBER_PASS; - - assertFalse(actionButton.disabled); - actionButton.click(); - const args = await browserProxy.whenCalled('addAccount'); - assertEquals(EXPECTED_USER, args[AddParams.PRINCIPAL_NAME]); - assertEquals(EXPECTED_PASS, args[AddParams.PASSWORD]); - assertEquals(EXPECTED_REMEMBER_PASS, args[AddParams.REMEMBER_PASSWORD]); - assertEquals(EXPECTED_CONFIG, args[AddParams.CONFIG]); - - // Should be false if a new account is added. See also - // AllowExistingIsTrueForPresetAccounts test. - assertFalse(args[AddParams.ALLOW_EXISTING]); - }); - - // If an account is preset, overwriting that account should be allowed. - test('AllowExistingIsTrueForPresetAccounts', async () => { - // Populate dialog with preset account. - createDialog(TEST_KERBEROS_ACCOUNTS[1]); - actionButton.click(); - const args = await browserProxy.whenCalled('addAccount'); - assertTrue(args[AddParams.ALLOW_EXISTING]); - }); - - // While an account is being added, the action button is disabled. - test('ActionButtonDisableWhileInProgress', async () => { - assertFalse(actionButton.disabled); - actionButton.click(); - assertTrue(actionButton.disabled); - await browserProxy.whenCalled('addAccount'); - assertFalse(actionButton.disabled); - }); - - // If the account has passwordWasRemembered === true and the user just - // clicks the 'Add' button, an empty password is submitted. - test('SubmitsEmptyPasswordIfRememberedPasswordIsUsed', async () => { - assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); - createDialog(TEST_KERBEROS_ACCOUNTS[1]); - actionButton.click(); - const args = await browserProxy.whenCalled('addAccount'); - assertEquals('', args[AddParams.PASSWORD]); - assertTrue(args[AddParams.REMEMBER_PASSWORD]); - }); - - // If the account has passwordWasRemembered === true and the user changes - // the password before clicking the action button, the changed password is - // submitted. - test('SubmitsChangedPasswordIfRememberedPasswordIsChanged', async () => { - assertTrue(TEST_KERBEROS_ACCOUNTS[1].passwordWasRemembered); - createDialog(TEST_KERBEROS_ACCOUNTS[1]); - password.inputElement.value = 'some edit'; - password.dispatchEvent(new CustomEvent('input')); - actionButton.click(); - const args = await browserProxy.whenCalled('addAccount'); - assertNotEquals('', args[AddParams.PASSWORD]); - assertTrue(args[AddParams.REMEMBER_PASSWORD]); - }); - - test('AdvancedConfigOpenClose', async () => { - assertTrue(!dialog.$$('#advancedConfigDialog')); - assertFalse(addDialog.hidden); - advancedConfigButton.click(); - Polymer.dom.flush(); - - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - assertTrue(!!advancedConfigDialog); - assertTrue(advancedConfigDialog.open); - assertTrue(addDialog.hidden); - const saveButton = advancedConfigDialog.querySelector('.action-button'); - assertFalse(saveButton.disabled); - saveButton.click(); - Polymer.dom.flush(); - assertTrue(saveButton.disabled); - - await browserProxy.whenCalled('validateConfig'); - Polymer.dom.flush(); - assertFalse(saveButton.disabled); - assertTrue(!dialog.$$('#advancedConfigDialog')); - assertFalse(addDialog.hidden); - assertTrue(addDialog.open); - }); - - test('AdvancedConfigurationSaveKeepsConfig', async () => { - advancedConfigButton.click(); - Polymer.dom.flush(); - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - assertTrue(!!advancedConfigDialog); - - // Change config and save. - const modifiedConfig = 'modified'; - advancedConfigDialog.querySelector('#config').value = modifiedConfig; - advancedConfigDialog.querySelector('.action-button').click(); - - // Changed value should stick. - await browserProxy.whenCalled('validateConfig'); - Polymer.dom.flush(); - assertConfig(modifiedConfig); - }); - - test('AdvancedConfigurationCancelResetsConfig', function() { - advancedConfigButton.click(); - Polymer.dom.flush(); - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - assertTrue(!!advancedConfigDialog); - - // Change config and cancel. - const prevConfig = advancedConfigDialog.querySelector('#config').value; - advancedConfigDialog.querySelector('#config').value = 'modified'; - advancedConfigDialog.querySelector('.cancel-button').click(); - Polymer.dom.flush(); - - // Changed value should NOT stick. - assertConfig(prevConfig); - }); - - test('AdvancedConfigurationDisabledByPolicy', function() { - assertTrue(TEST_KERBEROS_ACCOUNTS[2].isManaged); - createDialog(TEST_KERBEROS_ACCOUNTS[2]); - advancedConfigButton.click(); - Polymer.dom.flush(); - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - assertTrue(!!advancedConfigDialog); - assertTrue(!!advancedConfigDialog.querySelector( - '#advancedConfigPolicyIndicator')); - assertTrue(advancedConfigDialog.querySelector('#config').disabled); - }); - - test('AdvancedConfigurationValidationError', async () => { - advancedConfigButton.click(); - Polymer.dom.flush(); - const advancedConfigDialog = dialog.$$('#advancedConfigDialog'); - assertTrue(!!advancedConfigDialog); - - // Cause a validation error. - browserProxy.validateConfigResult = { - error: settings.KerberosErrorType.kBadConfig, - errorInfo: { - code: settings.KerberosConfigErrorCode.kKeyNotSupported, - lineIndex: 0 - } - }; - - // Clicking the action button (aka 'Save') validates the config. - advancedConfigDialog.querySelector('.action-button').click(); - - await browserProxy.whenCalled('validateConfig'); - - // Wait for dialog to process the 'validateConfig' result (sets error - // message etc.). - await test_util.flushTasks(); - - // Is some error text set? - const configError = - advancedConfigDialog.querySelector('#config-error-message'); - assertTrue(!!configError); - assertNotEquals(0, configError.innerText.length); - - // Is something selected? - const configElement = advancedConfigDialog.querySelector('#config'); - const textArea = configElement.$.input; - assertEquals(0, textArea.selectionStart); - assertNotEquals(0, textArea.selectionEnd); - - // Is the config dialog is still open? - assertTrue(advancedConfigDialog.open); - assertTrue(addDialog.hidden); - - // Was the config not accepted? - advancedConfigDialog.querySelector('.cancel-button').click(); - Polymer.dom.flush(); - assertConfig(loadTimeData.getString('defaultKerberosConfig')); - }); - - // addAccount: KerberosErrorType.kNetworkProblem spawns a general error. - test('AddAccountError_NetworkProblem', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kNetworkProblem, generalError); - }); - - // addAccount: KerberosErrorType.kParsePrincipalFailed spawns a username - // error. - test('AddAccountError_ParsePrincipalFailed', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kParsePrincipalFailed, username.$.error); - }); - - // addAccount: KerberosErrorType.kBadPrincipal spawns a username error. - test('AddAccountError_BadPrincipal', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kBadPrincipal, username.$.error); - }); - - // addAccount: KerberosErrorType.kDuplicatePrincipalName spawns a username - // error. - test('AddAccountError_DuplicatePrincipalName', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kDuplicatePrincipalName, username.$.error); - }); - - // addAccount: KerberosErrorType.kContactingKdcFailed spawns a username - // error. - test('AddAccountError_ContactingKdcFailed', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kContactingKdcFailed, username.$.error); - }); - - // addAccount: KerberosErrorType.kBadPassword spawns a password error. - test('AddAccountError_BadPassword', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kBadPassword, password.$.error); - }); - - // addAccount: KerberosErrorType.kPasswordExpired spawns a password error. - test('AddAccountError_PasswordExpired', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kPasswordExpired, password.$.error); - }); - - // addAccount: KerberosErrorType.kKdcDoesNotSupportEncryptionType spawns a - // general error. - test('AddAccountError_KdcDoesNotSupportEncryptionType', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kKdcDoesNotSupportEncryptionType, - generalError); - }); - - // addAccount: KerberosErrorType.kUnknown spawns a general error. - test('AddAccountError_Unknown', async () => { - await checkAddAccountError( - settings.KerberosErrorType.kUnknown, generalError); - }); + // Was the config not accepted? + advancedConfigDialog.querySelector('.cancel-button').click(); + flush(); + assertConfig(loadTimeData.getString('defaultKerberosConfig')); }); - // #cr_define_end - return {}; + // addAccount: KerberosErrorType.kNetworkProblem spawns a general error. + test('AddAccountError_NetworkProblem', async () => { + await checkAddAccountError(KerberosErrorType.kNetworkProblem, generalError); + }); + + // addAccount: KerberosErrorType.kParsePrincipalFailed spawns a username + // error. + test('AddAccountError_ParsePrincipalFailed', async () => { + await checkAddAccountError( + KerberosErrorType.kParsePrincipalFailed, username.$.error); + }); + + // addAccount: KerberosErrorType.kBadPrincipal spawns a username error. + test('AddAccountError_BadPrincipal', async () => { + await checkAddAccountError( + KerberosErrorType.kBadPrincipal, username.$.error); + }); + + // addAccount: KerberosErrorType.kDuplicatePrincipalName spawns a username + // error. + test('AddAccountError_DuplicatePrincipalName', async () => { + await checkAddAccountError( + KerberosErrorType.kDuplicatePrincipalName, username.$.error); + }); + + // addAccount: KerberosErrorType.kContactingKdcFailed spawns a username + // error. + test('AddAccountError_ContactingKdcFailed', async () => { + await checkAddAccountError( + KerberosErrorType.kContactingKdcFailed, username.$.error); + }); + + // addAccount: KerberosErrorType.kBadPassword spawns a password error. + test('AddAccountError_BadPassword', async () => { + await checkAddAccountError( + KerberosErrorType.kBadPassword, password.$.error); + }); + + // addAccount: KerberosErrorType.kPasswordExpired spawns a password error. + test('AddAccountError_PasswordExpired', async () => { + await checkAddAccountError( + KerberosErrorType.kPasswordExpired, password.$.error); + }); + + // addAccount: KerberosErrorType.kKdcDoesNotSupportEncryptionType spawns a + // general error. + test('AddAccountError_KdcDoesNotSupportEncryptionType', async () => { + await checkAddAccountError( + KerberosErrorType.kKdcDoesNotSupportEncryptionType, generalError); + }); + + // addAccount: KerberosErrorType.kUnknown spawns a general error. + test('AddAccountError_Unknown', async () => { + await checkAddAccountError(KerberosErrorType.kUnknown, generalError); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/kerberos_page_test.js b/chrome/test/data/webui/settings/chromeos/kerberos_page_test.js index 0b29e6e..12025a7 100644 --- a/chrome/test/data/webui/settings/chromeos/kerberos_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/kerberos_page_test.js
@@ -2,62 +2,51 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// clang-format off -// #import 'chrome://os-settings/chromeos/os_settings.js'; +import {KerberosAccountsBrowserProxyImpl, Route, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js'; +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -// #import {TestKerberosAccountsBrowserProxy} from './test_kerberos_accounts_browser_proxy.m.js'; -// #import {Router, Route, routes, KerberosAccountsBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js'; -// #import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; -// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {assertEquals, assertFalse} from '../../chai_assert.js'; -// clang-format on +import {TestKerberosAccountsBrowserProxy} from './test_kerberos_accounts_browser_proxy.js'; -cr.define('settings_kerberos_page', function() { - suite('KerberosPageTests', function() { - let browserProxy = null; +suite('KerberosPageTests', function() { + let browserProxy = null; - /** @type {SettingsKerberosPageElement} */ - let kerberosPage = null; + /** @type {SettingsKerberosPageElement} */ + let kerberosPage = null; - setup(function() { - settings.routes.BASIC = new settings.Route('/'), - settings.routes.KERBEROS = - settings.routes.BASIC.createSection('/kerberos', 'kerberos'); - settings.routes.KERBEROS_ACCOUNTS_V2 = - settings.routes.KERBEROS.createChild('/kerberos/kerberosAccounts'); + setup(function() { + routes.BASIC = new Route('/'), + routes.KERBEROS = routes.BASIC.createSection('/kerberos', 'kerberos'); + routes.KERBEROS_ACCOUNTS_V2 = + routes.KERBEROS.createChild('/kerberos/kerberosAccounts'); - settings.Router.resetInstanceForTesting( - new settings.Router(settings.routes)); + Router.resetInstanceForTesting(new Router(routes)); - browserProxy = new TestKerberosAccountsBrowserProxy(); - settings.KerberosAccountsBrowserProxyImpl.instance_ = browserProxy; - PolymerTest.clearBody(); - }); - - teardown(function() { - kerberosPage.remove(); - settings.Router.getInstance().resetRouteForTesting(); - settings.KerberosAccountsBrowserProxyImpl.instance_ = undefined; - }); - - test('Kerberos Section contains a link to Kerberos Accounts', () => { - kerberosPage = document.createElement('settings-kerberos-page'); - document.body.appendChild(kerberosPage); - Polymer.dom.flush(); - - // Sub-page trigger is shown. - const subpageTrigger = kerberosPage.shadowRoot.querySelector( - '#kerberos-accounts-subpage-trigger'); - assertFalse(subpageTrigger.hidden); - - // Sub-page trigger navigates to Kerberos Accounts V2. - subpageTrigger.click(); - assertEquals( - settings.Router.getInstance().getCurrentRoute(), - settings.routes.KERBEROS_ACCOUNTS_V2); - }); + browserProxy = new TestKerberosAccountsBrowserProxy(); + KerberosAccountsBrowserProxyImpl.instance_ = browserProxy; + PolymerTest.clearBody(); }); - // #cr_define_end - return {}; + teardown(function() { + kerberosPage.remove(); + Router.getInstance().resetRouteForTesting(); + KerberosAccountsBrowserProxyImpl.instance_ = undefined; + }); + + test('Kerberos Section contains a link to Kerberos Accounts', () => { + kerberosPage = document.createElement('settings-kerberos-page'); + document.body.appendChild(kerberosPage); + flush(); + + // Sub-page trigger is shown. + const subpageTrigger = kerberosPage.shadowRoot.querySelector( + '#kerberos-accounts-subpage-trigger'); + assertFalse(subpageTrigger.hidden); + + // Sub-page trigger navigates to Kerberos Accounts V2. + subpageTrigger.click(); + assertEquals( + Router.getInstance().getCurrentRoute(), routes.KERBEROS_ACCOUNTS_V2); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/onc_mojo_test.js b/chrome/test/data/webui/settings/chromeos/onc_mojo_test.js index a6114da4..c19c82a 100644 --- a/chrome/test/data/webui/settings/chromeos/onc_mojo_test.js +++ b/chrome/test/data/webui/settings/chromeos/onc_mojo_test.js
@@ -4,8 +4,6 @@ import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js'; -import {assertThrows} from '../../chai_assert.js'; - const mojom = chromeos.networkConfig.mojom; suite('OncMojoTest', () => {
diff --git a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js index 2a05c1e..a401bc0 100644 --- a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
@@ -11,7 +11,7 @@ import {TestAboutPageBrowserProxyChromeOS} from './test_about_page_browser_proxy_chromeos.js'; import {TestDeviceNameBrowserProxy} from './test_device_name_browser_proxy.js'; -import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.m.js'; +import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.js'; suite('AboutPageTest', function() { let page = null;
diff --git a/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js b/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js index 9ec847a..8eef326 100644 --- a/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js
@@ -5,17 +5,19 @@ import {LanguagesBrowserProxyImpl, LanguagesMetricsProxyImpl, LanguagesPageInteraction, LifetimeBrowserProxyImpl} from 'chrome://os-settings/chromeos/lazy_load.js'; import {CrSettingsPrefs, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js'; import {assert} from 'chrome://resources/js/assert.m.js'; +import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {waitAfterNextRender} from 'chrome://test/test_util.js'; + +import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; +import {fakeDataBind} from '../../test_util.js'; + import {getFakeLanguagePrefs} from './fake_language_settings_private.js'; import {FakeSettingsPrivate} from './fake_settings_private.js'; import {TestLanguagesBrowserProxy} from './test_os_languages_browser_proxy.js'; import {TestLanguagesMetricsProxy} from './test_os_languages_metrics_proxy.js'; -import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.m.js'; -import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; -import {fakeDataBind} from '../../test_util.js'; -import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; -import {waitAfterNextRender} from 'chrome://test/test_util.js'; +import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.js'; suite('languages page', () => { /** @type {!LanguageHelper} */
diff --git a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js index c0f5255b..e008489 100644 --- a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
@@ -12,8 +12,8 @@ import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; -import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.m.js'; -import {TestOsResetBrowserProxy} from './test_os_reset_browser_proxy.m.js'; +import {TestLifetimeBrowserProxy} from './test_os_lifetime_browser_proxy.js'; +import {TestOsResetBrowserProxy} from './test_os_reset_browser_proxy.js'; /** @enum {string} */ const TestNames = {
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js index 0fcaa73..5c03e37 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -390,8 +390,8 @@ ['InternetKnownNetworksPage', 'internet_known_networks_page_tests.js'], ['InternetSubpage', 'internet_subpage_tests.js'], ['InternetPage', 'internet_page_tests.js'], - ['KerberosAccounts', 'kerberos_accounts_test.m.js'], - ['KerberosPage', 'kerberos_page_test.m.js'], + ['KerberosAccounts', 'kerberos_accounts_test.js'], + ['KerberosPage', 'kerberos_page_test.js'], ['KeyboardShortcutBanner', 'keyboard_shortcut_banner_test.js'], ['LockScreenPage', 'lock_screen_tests.js'], ['ManageAccessibilityPage', 'manage_accessibility_page_tests.js'], @@ -430,7 +430,7 @@ ['NetworkProxySection', 'network_proxy_section_test.js'], ['NetworkSummary', 'network_summary_test.js'], ['NetworkSummaryItem', 'network_summary_item_test.js'], - ['OncMojoTest', 'onc_mojo_test.m.js'], + ['OncMojoTest', 'onc_mojo_test.js'], ['OsBluetoothPage', 'os_bluetooth_page_tests.js'], ['OsBluetoothPairingDialog', 'os_bluetooth_pairing_dialog_tests.js'], ['OsBluetoothSummary', 'os_bluetooth_summary_tests.js'], @@ -459,7 +459,7 @@ ['SearchSubpage', 'search_subpage_test.js'], ['SettingsTrafficCounters', 'settings_traffic_counters_test.js'], ['SmartInputsPage', 'smart_inputs_page_test.js'], - ['SmbPage', 'smb_shares_page_tests.m.js'], + ['SmbPage', 'smb_shares_page_tests.js'], ['SmartPrivacySubpage', 'smart_privacy_subpage_tests.js'], [ 'SwitchAccessActionAssignmentDialog', @@ -467,7 +467,7 @@ ], ['SwitchAccessSetupGuideDialog', 'switch_access_setup_guide_dialog_test.js'], ['SwitchAccessSubpage', 'switch_access_subpage_tests.js'], - ['TetherConnectionDialog', 'tether_connection_dialog_test.m.js'], + ['TetherConnectionDialog', 'tether_connection_dialog_test.js'], ['TextToSpeechSubpage', 'text_to_speech_subpage_tests.js'], ['TimezoneSelector', 'timezone_selector_test.js'], ['TimezoneSubpage', 'timezone_subpage_test.js'],
diff --git a/chrome/test/data/webui/settings/chromeos/personalization_page_test.js b/chrome/test/data/webui/settings/chromeos/personalization_page_test.js index f4f583b8..2de379a8 100644 --- a/chrome/test/data/webui/settings/chromeos/personalization_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/personalization_page_test.js
@@ -9,8 +9,8 @@ import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; -import {TestPersonalizationHubBrowserProxy} from './test_personalization_hub_browser_proxy.m.js'; -import {TestWallpaperBrowserProxy} from './test_wallpaper_browser_proxy.m.js'; +import {TestPersonalizationHubBrowserProxy} from './test_personalization_hub_browser_proxy.js'; +import {TestWallpaperBrowserProxy} from './test_wallpaper_browser_proxy.js'; let personalizationPage = null;
diff --git a/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js b/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js index f22e5162..2d3ad2c 100644 --- a/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
@@ -2,14 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// clang-format off -// #import 'chrome://os-settings/chromeos/lazy_load.js'; -// #import {TestBrowserProxy} from '../../test_browser_proxy.js'; -// #import {SmbMountResult, SmbBrowserProxyImpl} from 'chrome://os-settings/chromeos/lazy_load.js'; -// #import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; -// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -// #import {flushTasks} from 'chrome://test/test_util.js'; -// clang-format on +import {SmbBrowserProxyImpl, SmbMountResult} from 'chrome://os-settings/chromeos/lazy_load.js'; +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {assertFalse, assertTrue} from '../../chai_assert.js'; +import {TestBrowserProxy} from '../../test_browser_proxy.js'; /** @implements {smb_shares.SmbBrowserProxy} */ class TestSmbBrowserProxy extends TestBrowserProxy { @@ -45,7 +42,7 @@ setup(function() { smbBrowserProxy = new TestSmbBrowserProxy(); - smb_shares.SmbBrowserProxyImpl.instance_ = smbBrowserProxy; + SmbBrowserProxyImpl.instance_ = smbBrowserProxy; PolymerTest.clearBody(); @@ -55,12 +52,12 @@ const button = page.$$('#addShare'); assertTrue(!!button); button.click(); - Polymer.dom.flush(); + flush(); addDialog = page.$$('add-smb-share-dialog'); assertTrue(!!addDialog); - Polymer.dom.flush(); + flush(); }); teardown(function() { @@ -173,7 +170,7 @@ page.prefs = { network_file_shares: {allowed: {value: false}}, }; - Polymer.dom.flush(); + flush(); assertTrue(!!page.$$('cr-policy-pref-indicator')); assertTrue(button.disabled); @@ -203,13 +200,13 @@ dropDown.value = 'kerberos'; dropDown.dispatchEvent(new CustomEvent('change')); - Polymer.dom.flush(); + flush(); expectTrue(credentials.hidden); dropDown.value = 'credentials'; dropDown.dispatchEvent(new CustomEvent('change')); - Polymer.dom.flush(); + flush(); expectFalse(credentials.hidden); }); @@ -233,12 +230,12 @@ assertFalse(button.disabled); button.click(); - Polymer.dom.flush(); + flush(); addDialog = page.$$('add-smb-share-dialog'); assertTrue(!!addDialog); - Polymer.dom.flush(); + flush(); const openDialogButton = page.$$('#addShare'); openDialogButton.click();
diff --git a/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js index 1607ff45e..a315810d 100644 --- a/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js
@@ -2,15 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// clang-format off -// #import 'chrome://os-settings/chromeos/os_settings.js'; - -// #import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.js'; -// #import {KerberosErrorType, KerberosConfigErrorCode} from 'chrome://os-settings/chromeos/os_settings.js'; -// clang-format on +import {KerberosConfigErrorCode, KerberosErrorType} from 'chrome://os-settings/chromeos/os_settings.js'; +import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.js'; // List of fake accounts. -/* #export */ const TEST_KERBEROS_ACCOUNTS = [ +export const TEST_KERBEROS_ACCOUNTS = [ { principalName: 'user@REALM', config: 'config1', @@ -43,8 +39,8 @@ } ]; -/** @implements {settings.KerberosAccountsBrowserProxy} */ -/* #export */ class TestKerberosAccountsBrowserProxy extends TestBrowserProxy { +/** @implements {KerberosAccountsBrowserProxy} */ +export class TestKerberosAccountsBrowserProxy extends TestBrowserProxy { constructor() { super([ 'getAccounts', @@ -55,12 +51,12 @@ ]); // Simulated error from an addAccount call. - this.addAccountError = settings.KerberosErrorType.kNone; + this.addAccountError = KerberosErrorType.kNone; // Simulated error from a validateConfig call. this.validateConfigResult = { - error: settings.KerberosErrorType.kNone, - errorInfo: {code: settings.KerberosConfigErrorCode.kNone} + error: KerberosErrorType.kNone, + errorInfo: {code: KerberosConfigErrorCode.kNone} }; } @@ -81,7 +77,7 @@ /** @override */ removeAccount(account) { this.methodCalled('removeAccount', account); - return Promise.resolve(settings.KerberosErrorType.kNone); + return Promise.resolve(KerberosErrorType.kNone); } /** @override */
diff --git a/chrome/test/data/webui/settings/chromeos/test_os_lifetime_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_os_lifetime_browser_proxy.js index 1e0c2698..037346e 100644 --- a/chrome/test/data/webui/settings/chromeos/test_os_lifetime_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_os_lifetime_browser_proxy.js
@@ -2,43 +2,35 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// #import {TestBrowserProxy} from '../../test_browser_proxy.js'; +import {TestBrowserProxy} from '../../test_browser_proxy.js'; -cr.define('settings', function() { - /** - * A test version of LifetimeBrowserProxy. - */ - /* #export */ class TestLifetimeBrowserProxy extends TestBrowserProxy { - constructor() { - const methodNames = ['restart', 'relaunch']; - methodNames.push('signOutAndRestart', 'factoryReset'); - super(methodNames); - } - - /** @override */ - restart() { - this.methodCalled('restart'); - } - - /** @override */ - relaunch() { - this.methodCalled('relaunch'); - } - - /** @override */ - signOutAndRestart() { - this.methodCalled('signOutAndRestart'); - } - - /** @override */ - factoryReset(requestTpmFirmwareUpdate) { - this.methodCalled('factoryReset', requestTpmFirmwareUpdate); - } - +/** + * A test version of LifetimeBrowserProxy. + */ +export class TestLifetimeBrowserProxy extends TestBrowserProxy { + constructor() { + const methodNames = ['restart', 'relaunch']; + methodNames.push('signOutAndRestart', 'factoryReset'); + super(methodNames); } - // #cr_define_end - return { - TestLifetimeBrowserProxy: TestLifetimeBrowserProxy, - }; -}); + /** @override */ + restart() { + this.methodCalled('restart'); + } + + /** @override */ + relaunch() { + this.methodCalled('relaunch'); + } + + /** @override */ + signOutAndRestart() { + this.methodCalled('signOutAndRestart'); + } + + /** @override */ + factoryReset(requestTpmFirmwareUpdate) { + this.methodCalled('factoryReset', requestTpmFirmwareUpdate); + } +}
diff --git a/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js index 87716a6..5fe830b 100644 --- a/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js
@@ -2,25 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// #import {TestBrowserProxy} from '../../test_browser_proxy.js'; +import {TestBrowserProxy} from '../../test_browser_proxy.js'; -cr.define('reset_page', function() { - /** @implements {settings.OsResetBrowserProxy} */ - /* #export */ class TestOsResetBrowserProxy extends TestBrowserProxy { - constructor() { - super([ - 'onPowerwashDialogShow', - ]); - } - - /** @override */ - onPowerwashDialogShow() { - this.methodCalled('onPowerwashDialogShow'); - } +/** @implements {OsResetBrowserProxy} */ +export class TestOsResetBrowserProxy extends TestBrowserProxy { + constructor() { + super([ + 'onPowerwashDialogShow', + ]); } - // #cr_define_end - return { - TestOsResetBrowserProxy: TestOsResetBrowserProxy, - }; -}); + /** @override */ + onPowerwashDialogShow() { + this.methodCalled('onPowerwashDialogShow'); + } +}
diff --git a/chrome/test/data/webui/settings/chromeos/test_personalization_hub_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_personalization_hub_browser_proxy.js index 1241c10..4e63d5c 100644 --- a/chrome/test/data/webui/settings/chromeos/test_personalization_hub_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_personalization_hub_browser_proxy.js
@@ -2,22 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// #import {TestBrowserProxy} from '../../test_browser_proxy.js'; +import {TestBrowserProxy} from '../../test_browser_proxy.js'; -cr.define('settings', function() { - /** @implements {settings.PersonalizationHubBrowserProxy} */ - /* #export */ class TestPersonalizationHubBrowserProxy extends - TestBrowserProxy { - constructor() { - super(['openPersonalizationHub']); - } - - /** @override */ - openPersonalizationHub() { - this.methodCalled('openPersonalizationHub'); - } +/** @implements {PersonalizationHubBrowserProxy} */ +export class TestPersonalizationHubBrowserProxy extends TestBrowserProxy { + constructor() { + super(['openPersonalizationHub']); } - // #cr_define_end - return {TestPersonalizationHubBrowserProxy}; -}); + /** @override */ + openPersonalizationHub() { + this.methodCalled('openPersonalizationHub'); + } +}
diff --git a/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js index 2d2acc5..b702354 100644 --- a/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js
@@ -2,50 +2,43 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// #import {TestBrowserProxy} from '../../test_browser_proxy.js'; +import {TestBrowserProxy} from '../../test_browser_proxy.js'; -cr.define('settings', function() { - /** @implements {settings.WallpaperBrowserProxy} */ - /* #export */ class TestWallpaperBrowserProxy extends TestBrowserProxy { - constructor() { - super([ - 'isWallpaperSettingVisible', - 'isWallpaperPolicyControlled', - 'openWallpaperManager', - ]); +/** @implements {WallpaperBrowserProxy} */ +export class TestWallpaperBrowserProxy extends TestBrowserProxy { + constructor() { + super([ + 'isWallpaperSettingVisible', + 'isWallpaperPolicyControlled', + 'openWallpaperManager', + ]); - /** @private */ - this.isWallpaperSettingVisible_ = true; + /** @private */ + this.isWallpaperSettingVisible_ = true; - /** @private */ - this.isWallpaperPolicyControlled_ = false; - } - - /** @override */ - isWallpaperSettingVisible() { - this.methodCalled('isWallpaperSettingVisible'); - return Promise.resolve(true); - } - - /** @override */ - isWallpaperPolicyControlled() { - this.methodCalled('isWallpaperPolicyControlled'); - return Promise.resolve(this.isWallpaperPolicyControlled_); - } - - /** @override */ - openWallpaperManager() { - this.methodCalled('openWallpaperManager'); - } - - /** @param {boolean} Whether the wallpaper is policy controlled. */ - setIsWallpaperPolicyControlled(isPolicyControlled) { - this.isWallpaperPolicyControlled_ = isPolicyControlled; - } + /** @private */ + this.isWallpaperPolicyControlled_ = false; } - // #cr_define_end - return { - TestWallpaperBrowserProxy: TestWallpaperBrowserProxy, - }; -}); + /** @override */ + isWallpaperSettingVisible() { + this.methodCalled('isWallpaperSettingVisible'); + return Promise.resolve(true); + } + + /** @override */ + isWallpaperPolicyControlled() { + this.methodCalled('isWallpaperPolicyControlled'); + return Promise.resolve(this.isWallpaperPolicyControlled_); + } + + /** @override */ + openWallpaperManager() { + this.methodCalled('openWallpaperManager'); + } + + /** @param {boolean} Whether the wallpaper is policy controlled. */ + setIsWallpaperPolicyControlled(isPolicyControlled) { + this.isWallpaperPolicyControlled_ = isPolicyControlled; + } +}
diff --git a/chrome/test/data/webui/settings/chromeos/tether_connection_dialog_test.js b/chrome/test/data/webui/settings/chromeos/tether_connection_dialog_test.js index f5481d61..42ea1fa 100644 --- a/chrome/test/data/webui/settings/chromeos/tether_connection_dialog_test.js +++ b/chrome/test/data/webui/settings/chromeos/tether_connection_dialog_test.js
@@ -2,11 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// clang-format off -// #import 'chrome://os-settings/chromeos/os_settings.js'; +import 'chrome://os-settings/chromeos/os_settings.js'; -// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -// clang-format on +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; suite('TetherConnectionDialog', function() { /** @type {!TetherConnectionDialogElement|undefined} */ @@ -15,7 +13,7 @@ setup(function() { tetherDialog = document.createElement('tether-connection-dialog'); document.body.appendChild(tetherDialog); - Polymer.dom.flush(); + flush(); }); test('Battery percentage', function() { @@ -30,7 +28,7 @@ }, }, }; - Polymer.dom.flush(); + flush(); const batteryEl = tetherDialog.$.hostDeviceTextBattery; assertEquals('75% Battery', batteryEl.innerText.trim());
diff --git a/chromecast/cast_core/test/cast_core_screenshot_test.py b/chromecast/cast_core/test/cast_core_screenshot_test.py index 43ba166b..b14cb96 100644 --- a/chromecast/cast_core/test/cast_core_screenshot_test.py +++ b/chromecast/cast_core/test/cast_core_screenshot_test.py
@@ -23,7 +23,7 @@ @classmethod def SetUpProcess(cls): - super(cls, InfoCollectionTest).SetUpProcess() + super(cls, ScreenshotTest).SetUpProcess() cls.SetBrowserOptions(cls._finder_options) cls.StartBrowser() cls.tab = cls.browser.tabs[0]
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 9b38c5f..3e0599c 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -17,6 +17,7 @@ <output filename="chromeos_strings_bs.pak" type="data_package" lang="bs" /> <output filename="chromeos_strings_ca.pak" type="data_package" lang="ca" /> <output filename="chromeos_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="chromeos_strings_cy.pak" type="data_package" lang="cy" /> <output filename="chromeos_strings_da.pak" type="data_package" lang="da" /> <output filename="chromeos_strings_de.pak" type="data_package" lang="de" /> <output filename="chromeos_strings_el.pak" type="data_package" lang="el" />
diff --git a/chromeos/components/quick_answers/public/cpp/quick_answers_state.h b/chromeos/components/quick_answers/public/cpp/quick_answers_state.h index e925d586..f67d7e0 100644 --- a/chromeos/components/quick_answers/public/cpp/quick_answers_state.h +++ b/chromeos/components/quick_answers/public/cpp/quick_answers_state.h
@@ -83,21 +83,7 @@ use_text_annotator_for_testing_ = true; } - private: - void InitializeObserver(QuickAnswersStateObserver* observer); - - // Called when the related preferences are obtained from the pref service. - void UpdateSettingsEnabled(); - void UpdateConsentStatus(); - void UpdateDefinitionEnabled(); - void UpdateTranslationEnabled(); - void UpdateUnitConversionEnabled(); - void OnApplicationLocaleReady(); - void UpdatePreferredLanguages(); - - // Called when the feature eligibility might change. - void UpdateEligibility(); - + protected: // Whether the Quick Answers is enabled in system settings. bool settings_enabled_ = false; @@ -121,6 +107,23 @@ // (ex. "en-US,zh,fr"). std::string preferred_languages_; + base::ObserverList<QuickAnswersStateObserver> observers_; + + private: + void InitializeObserver(QuickAnswersStateObserver* observer); + + // Called when the related preferences are obtained from the pref service. + void UpdateSettingsEnabled(); + void UpdateConsentStatus(); + void UpdateDefinitionEnabled(); + void UpdateTranslationEnabled(); + void UpdateUnitConversionEnabled(); + void OnApplicationLocaleReady(); + void UpdatePreferredLanguages(); + + // Called when the feature eligibility might change. + void UpdateEligibility(); + // Whether the Quick Answers feature is eligible. The value is derived from a // number of other states. bool is_eligible_ = false; @@ -136,8 +139,6 @@ // Observes user profile prefs for the Assistant. std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; - - base::ObserverList<QuickAnswersStateObserver> observers_; }; #endif // CHROMEOS_COMPONENTS_QUICK_ANSWERS_PUBLIC_CPP_QUICK_ANSWERS_STATE_H_
diff --git a/chromeos/crosapi/mojom/prefs.mojom b/chromeos/crosapi/mojom/prefs.mojom index e20d85a..257c911 100644 --- a/chromeos/crosapi/mojom/prefs.mojom +++ b/chromeos/crosapi/mojom/prefs.mojom
@@ -67,6 +67,24 @@ // M98: prefs::kAccessibilityVirtualKeyboardEnabled (extension). [MinVersion=3] kAccessibilityVirtualKeyboardEnabled = 20, + // M100: quick_answers::prefs::kQuickAnswersEnabled (profile) + [MinVersion=4] kQuickAnswersEnabled = 21, + // M100: quick_answers::prefs::kQuickAnswersConsentStatus (profile) + [MinVersion=4] kQuickAnswersConsentStatus = 22, + // M100: quick_answers::prefs::kQuickAnswersDefinitionEnabled (profile) + [MinVersion=4] kQuickAnswersDefinitionEnabled = 23, + // M100: quick_answers::prefs::kQuickAnswersTranslationEnabled (profile) + [MinVersion=4] kQuickAnswersTranslationEnabled = 24, + // M100: quick_answers::prefs::kQuickAnswersUnitConversionEnabled (profile) + [MinVersion=4] kQuickAnswersUnitConversionEnabled = 25, + // M100: quick_answers::prefs::kQuickAnswersNoticeImpressionCount (profile) + [MinVersion=4] kQuickAnswersNoticeImpressionCount = 26, + // M100: quick_answers::prefs::kQuickAnswersNoticeImpressionDuration (profile) + [MinVersion=4] kQuickAnswersNoticeImpressionDuration = 27, + // M100: language::prefs::kPreferredLanguages (profile) + [MinVersion=4] kPreferredLanguages = 28, + // M100: language::prefs::kApplicationLocale (profile) + [MinVersion=4] kApplicationLocale = 29, }; // Information about who or what is controlling a particular pref. This is used
diff --git a/chromeos/services/assistant/public/shared/BUILD.gn b/chromeos/services/assistant/public/shared/BUILD.gn index f6fb5313..b4b767c4 100644 --- a/chromeos/services/assistant/public/shared/BUILD.gn +++ b/chromeos/services/assistant/public/shared/BUILD.gn
@@ -16,7 +16,7 @@ "utils.h", ] - if (enable_cros_libassistant) { + if (is_chromeos && is_chrome_branded) { sources += [ "//chromeos/assistant/internal/constants.cc" ] } else { sources += [ "constants.cc" ]
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni index da8e4d6..16b296e8 100644 --- a/chromeos/tast_control.gni +++ b/chromeos/tast_control.gni
@@ -237,6 +237,9 @@ "crostini.SecureCopyPaste.paste_wayland_bullseye_stable", "crostini.UninstallInvalidApp.buster_stable", "crostini.Xattrs.buster_stable", + "crostini.NoSharedFolder.bullseye_stable", + "crostini.Notify.bullseye_stable", + "crostini.PackageInfo.bullseye_stable", # https://crbug.com/1312908 "policy.DefaultNotificationsSetting",
diff --git a/components/BUILD.gn b/components/BUILD.gn index f16d6ca..56264a1 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/features.gni") import("//build/config/ui.gni") import("//components/nacl/features.gni") +import("//components/optimization_guide/features.gni") import("//components/safe_browsing/buildflags.gni") import("//extensions/buildflags/buildflags.gni") import("//media/media_options.gni") @@ -235,6 +236,13 @@ "//components/webdata_services:unit_tests", ] + if (build_with_internal_optimization_guide && is_android) { + loadable_module_deps = [ + "//components/optimization_guide/internal:optimization_guide_internal", + ] + loadable_modules = [ "$root_out_dir/liboptimization_guide_internal.so" ] + } + data_deps = [ "//testing/buildbot/filters:components_unittests_filters" ] if (toolkit_views) {
diff --git a/components/components_chromium_strings.grd b/components/components_chromium_strings.grd index fc7c50f..5727953 100644 --- a/components/components_chromium_strings.grd +++ b/components/components_chromium_strings.grd
@@ -17,6 +17,7 @@ <output filename="components_chromium_strings_bs.pak" type="data_package" lang="bs" /> <output filename="components_chromium_strings_ca.pak" type="data_package" lang="ca" /> <output filename="components_chromium_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="components_chromium_strings_cy.pak" type="data_package" lang="cy" /> <output filename="components_chromium_strings_da.pak" type="data_package" lang="da" /> <output filename="components_chromium_strings_de.pak" type="data_package" lang="de" /> <output filename="components_chromium_strings_el.pak" type="data_package" lang="el" /> @@ -221,7 +222,7 @@ and deselect any proxies that have been selected. </message> </if> - <if expr="not chromeos_ash and is_posix and not is_macosx and not is_android and not is_ios"> + <if expr="not chromeos_ash and not chromeos_lacros and is_posix and not is_macosx and not is_android and not is_ios"> <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Linux instructions for disabling use of a proxy server."> Go to the Chromium menu >
diff --git a/components/components_google_chrome_strings.grd b/components/components_google_chrome_strings.grd index e35e891f..3863f41 100644 --- a/components/components_google_chrome_strings.grd +++ b/components/components_google_chrome_strings.grd
@@ -17,6 +17,7 @@ <output filename="components_google_chrome_strings_bs.pak" type="data_package" lang="bs" /> <output filename="components_google_chrome_strings_ca.pak" type="data_package" lang="ca" /> <output filename="components_google_chrome_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="components_google_chrome_strings_cy.pak" type="data_package" lang="cy" /> <output filename="components_google_chrome_strings_da.pak" type="data_package" lang="da" /> <output filename="components_google_chrome_strings_de.pak" type="data_package" lang="de" /> <output filename="components_google_chrome_strings_el.pak" type="data_package" lang="el" /> @@ -228,7 +229,7 @@ and deselect any proxies that have been selected. </message> </if> - <if expr="not chromeos_ash and is_posix and not is_macosx and not is_android and not is_ios"> + <if expr="not chromeos_ash and not chromeos_lacros and is_posix and not is_macosx and not is_android and not is_ios"> <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Linux instructions for disabling use of a proxy server."> Go to the Chrome menu >
diff --git a/components/components_locale_settings.grd b/components/components_locale_settings.grd index 955981d..ad997ad 100644 --- a/components/components_locale_settings.grd +++ b/components/components_locale_settings.grd
@@ -15,6 +15,7 @@ <output filename="components_locale_settings_bs.pak" type="data_package" lang="bs" /> <output filename="components_locale_settings_ca.pak" type="data_package" lang="ca" /> <output filename="components_locale_settings_cs.pak" type="data_package" lang="cs" /> + <output filename="components_locale_settings_cy.pak" type="data_package" lang="cy" /> <output filename="components_locale_settings_da.pak" type="data_package" lang="da" /> <output filename="components_locale_settings_de.pak" type="data_package" lang="de" /> <output filename="components_locale_settings_el.pak" type="data_package" lang="el" />
diff --git a/components/components_strings.grd b/components/components_strings.grd index 9765aee..9665c68 100644 --- a/components/components_strings.grd +++ b/components/components_strings.grd
@@ -17,6 +17,7 @@ <output filename="components_strings_bs.pak" type="data_package" lang="bs" /> <output filename="components_strings_ca.pak" type="data_package" lang="ca" /> <output filename="components_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="components_strings_cy.pak" type="data_package" lang="cy" /> <output filename="components_strings_da.pak" type="data_package" lang="da" /> <output filename="components_strings_de.pak" type="data_package" lang="de" /> <output filename="components_strings_el.pak" type="data_package" lang="el" />
diff --git a/components/error_page_strings.grdp b/components/error_page_strings.grdp index 0a6230b..b85dde0a 100644 --- a/components/error_page_strings.grdp +++ b/components/error_page_strings.grdp
@@ -89,7 +89,7 @@ <ph name="PLATFORM_TEXT">$1<ex>Goto the wrench menu and choose Fix It.</ex></ph> </message> </if> - <if expr="chromeos_ash"> + <if expr="chromeos_ash or chromeos_lacros"> <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Chrome OS instructions for disabling use of a proxy server."> You can disable any proxies configured for a connection from the settings page. </message>
diff --git a/components/new_or_sad_tab_strings.grdp b/components/new_or_sad_tab_strings.grdp index 7048f47..4296e1c 100644 --- a/components/new_or_sad_tab_strings.grdp +++ b/components/new_or_sad_tab_strings.grdp
@@ -51,7 +51,7 @@ Open page in a new Incognito window (⇧⌘N) </message> </if> - <if expr="is_win or is_linux or is_fuchsia or chromeos_ash"> + <if expr="is_win or is_linux or is_fuchsia or chromeos_ash or chromeos_lacros"> <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode."> Open page in a new Incognito window (Ctrl-Shift-N) </message> @@ -61,22 +61,22 @@ Open page in a new Incognito tab </message> </if> - <if expr="is_macosx or chromeos_ash"> + <if expr="is_macosx or chromeos_ash or chromeos_lacros"> <message name="IDS_SAD_TAB_RELOAD_CLOSE_TABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other Chrome tabs or apps running on their computer (Mac, Chrome OS)."> Close other tabs or apps </message> </if> - <if expr="is_linux and not chromeos_ash"> + <if expr="is_linux and not chromeos_ash and not chromeos_lacros"> <message name="IDS_SAD_TAB_RELOAD_CLOSE_TABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other Chrome tabs or programs running on their computer."> Close other tabs or programs </message> </if> - <if expr="is_macosx or chromeos_ash or is_ios"> + <if expr="is_macosx or chromeos_ash or chromeos_lacros or is_ios"> <message name="IDS_SAD_TAB_RELOAD_CLOSE_NOTABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other apps running on their computer or device."> Close other apps </message> </if> - <if expr="is_linux and not chromeos_ash"> + <if expr="is_linux and not chromeos_ash and not chromeos_lacros"> <message name="IDS_SAD_TAB_RELOAD_CLOSE_NOTABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other programs running on their computer (Linux)."> Close other programs </message> @@ -91,7 +91,7 @@ Restart Chromium </message> </if> - <if expr="is_win or is_linux or is_macosx or is_fuchsia or chromeos_ash"> + <if expr="is_win or is_linux or is_macosx or is_fuchsia or chromeos_ash or chromeos_lacros"> <message name="IDS_SAD_TAB_RELOAD_RESTART_DEVICE" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to restart their computer."> Restart your computer </message> @@ -106,11 +106,11 @@ Learn more </message> </if> - <if expr="is_win or is_linux or is_macosx or is_fuchsia or chromeos_ash"> + <if expr="is_win or is_linux or is_macosx or is_fuchsia or chromeos_ash or chromeos_lacros"> <message name="IDS_SAD_TAB_ERROR_CODE" desc="The message displayed on the crashed web page indicating the type of the crash."> Error code: <ph name="ERROR_CODE">$1<ex>STATUS_ACCESS_VIOLATION</ex></ph> </message> -</if> + </if> <!-- New Tab --> <message name="IDS_NEW_TAB_TITLE"
diff --git a/components/omnibox/resources/omnibox_pedal_synonyms.grd b/components/omnibox/resources/omnibox_pedal_synonyms.grd index 004737b..2a78e64 100644 --- a/components/omnibox/resources/omnibox_pedal_synonyms.grd +++ b/components/omnibox/resources/omnibox_pedal_synonyms.grd
@@ -18,6 +18,7 @@ <output filename="omnibox_pedal_synonyms_bs.pak" type="data_package" lang="bs" /> <output filename="omnibox_pedal_synonyms_ca.pak" type="data_package" lang="ca" /> <output filename="omnibox_pedal_synonyms_cs.pak" type="data_package" lang="cs" /> + <output filename="omnibox_pedal_synonyms_cy.pak" type="data_package" lang="cy" /> <output filename="omnibox_pedal_synonyms_da.pak" type="data_package" lang="da" /> <output filename="omnibox_pedal_synonyms_de.pak" type="data_package" lang="de" /> <output filename="omnibox_pedal_synonyms_el.pak" type="data_package" lang="el" />
diff --git a/components/omnibox/resources/omnibox_resources.grd b/components/omnibox/resources/omnibox_resources.grd index 43a132a8..673ecd7 100644 --- a/components/omnibox/resources/omnibox_resources.grd +++ b/components/omnibox/resources/omnibox_resources.grd
@@ -19,6 +19,7 @@ <output filename="omnibox_resources_bs.pak" type="data_package" lang="bs" /> <output filename="omnibox_resources_ca.pak" type="data_package" lang="ca" /> <output filename="omnibox_resources_cs.pak" type="data_package" lang="cs" /> + <output filename="omnibox_resources_cy.pak" type="data_package" lang="cy" /> <output filename="omnibox_resources_da.pak" type="data_package" lang="da" /> <output filename="omnibox_resources_de.pak" type="data_package" lang="de" /> <output filename="omnibox_resources_el.pak" type="data_package" lang="el" />
diff --git a/components/optimization_guide/core/BUILD.gn b/components/optimization_guide/core/BUILD.gn index 4b4691d..9abc153 100644 --- a/components/optimization_guide/core/BUILD.gn +++ b/components/optimization_guide/core/BUILD.gn
@@ -232,7 +232,8 @@ "//services/network/public/cpp", "//url:url", ] - if (build_with_tflite_lib && build_with_internal_optimization_guide) { + if (!is_android && build_with_tflite_lib && + build_with_internal_optimization_guide) { data_deps = [ "//components/optimization_guide/internal:optimization_guide_internal", ]
diff --git a/components/optimization_guide/core/entity_annotator_native_library.cc b/components/optimization_guide/core/entity_annotator_native_library.cc index 57515da..8f637453 100644 --- a/components/optimization_guide/core/entity_annotator_native_library.cc +++ b/components/optimization_guide/core/entity_annotator_native_library.cc
@@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "base/path_service.h" #include "build/build_config.h" #include "components/optimization_guide/core/model_util.h" @@ -85,6 +86,9 @@ base_dir.AppendASCII( base::GetNativeLibraryName("optimization_guide_internal")), &error); + base::UmaHistogramBoolean( + "OptimizationGuide.EntityAnnotatorNativeLibrary.InitiatedSuccessfully", + (native_library != nullptr)); if (!native_library) { LOG(ERROR) << "Failed to initialize optimization guide internal: " << error.ToString();
diff --git a/components/optimization_guide/core/entity_annotator_native_library_unittest.cc b/components/optimization_guide/core/entity_annotator_native_library_unittest.cc index 0839193..20de5f801 100644 --- a/components/optimization_guide/core/entity_annotator_native_library_unittest.cc +++ b/components/optimization_guide/core/entity_annotator_native_library_unittest.cc
@@ -4,6 +4,7 @@ #include "components/optimization_guide/core/entity_annotator_native_library.h" +#include "base/test/metrics/histogram_tester.h" #include "testing/gtest/include/gtest/gtest.h" namespace optimization_guide { @@ -12,10 +13,16 @@ using EntityAnnotatorNativeLibraryTest = ::testing::Test; TEST_F(EntityAnnotatorNativeLibraryTest, CanCreateValidLibrary) { + base::HistogramTester histogram_tester; + std::unique_ptr<EntityAnnotatorNativeLibrary> lib = EntityAnnotatorNativeLibrary::Create(/*should_provide_filter_path=*/true); ASSERT_TRUE(lib); EXPECT_TRUE(lib->IsValid()); + + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.EntityAnnotatorNativeLibrary.InitiatedSuccessfully", + true, 1); } } // namespace
diff --git a/components/optimization_guide/core/page_entities_model_executor_impl.cc b/components/optimization_guide/core/page_entities_model_executor_impl.cc index 906767f..bbf144ee 100644 --- a/components/optimization_guide/core/page_entities_model_executor_impl.cc +++ b/components/optimization_guide/core/page_entities_model_executor_impl.cc
@@ -123,6 +123,9 @@ entity_annotator_ = entity_annotator_native_library_->CreateEntityAnnotator(model_info); + base::UmaHistogramBoolean( + "OptimizationGuide.PageEntitiesModelExecutor.CreatedSuccessfully", + entity_annotator_ != nullptr); } void EntityAnnotatorHolder::AnnotateEntitiesMetadataModelOnBackgroundThread(
diff --git a/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc b/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc index 96f8ca80..37591c5 100644 --- a/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc +++ b/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc
@@ -7,6 +7,7 @@ #include "base/observer_list.h" #include "base/path_service.h" #include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "components/optimization_guide/core/model_util.h" #include "components/optimization_guide/core/optimization_guide_util.h" @@ -156,6 +157,8 @@ }; TEST_F(PageEntitiesModelExecutorImplTest, CreateNoMetadata) { + base::HistogramTester histogram_tester; + std::unique_ptr<ModelInfo> model_info = TestModelInfoBuilder().Build(); ASSERT_TRUE(model_info); PushModelInfoToObservers(*model_info); @@ -163,9 +166,15 @@ // We expect that there will be no model to evaluate even for this input that // has output in the test model. EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt); + + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.PageEntitiesModelExecutor.CreatedSuccessfully", false, + 1); } TEST_F(PageEntitiesModelExecutorImplTest, CreateMetadataWrongType) { + base::HistogramTester histogram_tester; + proto::Any any; any.set_type_url(any.GetTypeName()); proto::FieldTrial garbage; @@ -183,9 +192,15 @@ // We expect that there will be no model to evaluate even for this input that // has output in the test model. EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt); + + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.PageEntitiesModelExecutor.CreatedSuccessfully", false, + 1); } TEST_F(PageEntitiesModelExecutorImplTest, CreateNoSlices) { + base::HistogramTester histogram_tester; + proto::Any any; proto::PageEntitiesModelMetadata metadata; any.set_type_url(metadata.GetTypeName()); @@ -203,6 +218,10 @@ // We expect that there will be no model to evaluate even for this input that // has output in the test model. EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt); + + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.PageEntitiesModelExecutor.CreatedSuccessfully", false, + 1); } TEST_F(PageEntitiesModelExecutorImplTest, CreateMissingFiles) { @@ -223,6 +242,8 @@ }; // Remove one file for each iteration and make sure it fails. for (const auto& missing_file_name : expected_additional_files) { + base::HistogramTester histogram_tester; + // Make a copy of the expected files and remove the one file from the set. base::flat_set<std::string> additional_files = expected_additional_files; additional_files.erase(missing_file_name); @@ -243,6 +264,10 @@ // We expect that there will be no model to evaluate even for this input // that has output in the test model. EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt); + + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.PageEntitiesModelExecutor.CreatedSuccessfully", + false, 1); } }
diff --git a/components/optimization_guide/features.gni b/components/optimization_guide/features.gni index 2ed17e31..1fa2b566 100644 --- a/components/optimization_guide/features.gni +++ b/components/optimization_guide/features.gni
@@ -16,6 +16,7 @@ # # If changing the value of this, you MUST also update the following files depending on the # platform: + # Android: Internal expectations files that verify the native libraries are compiled into the Android binary. # ChromeOS: //lib/chrome_util.py in the Chromite repo (ex: https://crrev.com/c/3437291) # Linux: Internal archive files. //chrome/installer/linux/common/installer.include handles the # relevant files not being present. @@ -23,8 +24,8 @@ # Windows: //chrome/installer/mini_installer/chrome.release and internal archive files # # The library this pulls in depends on open-source LevelDB which is not supported for Fuchsia. - # Android and iOS should just work but are not included in the set we release for, so we do - # not needlessly increase the binary. + # iOS should work but is not included in the set we release for, so we do + # not needlessly increase the binary size. build_with_internal_optimization_guide = - is_chrome_branded && !is_android && !is_ios && !is_fuchsia + is_chrome_branded && !is_ios && !is_fuchsia }
diff --git a/components/policy/core/browser/cloud/user_policy_signin_service_base.h b/components/policy/core/browser/cloud/user_policy_signin_service_base.h index b6658c75..cbb425fe 100644 --- a/components/policy/core/browser/cloud/user_policy_signin_service_base.h +++ b/components/policy/core/browser/cloud/user_policy_signin_service_base.h
@@ -168,6 +168,10 @@ signin::ConsentLevel consent_level() const { return consent_level_; } + scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory() { + return system_url_loader_factory_; + } + private: // Returns a CloudPolicyClient to perform a registration with the DM server, // or NULL if |username| shouldn't register for policy management.
diff --git a/components/policy/core/browser/cloud/user_policy_signin_service_util.cc b/components/policy/core/browser/cloud/user_policy_signin_service_util.cc index b8c14a0b..7371aff 100644 --- a/components/policy/core/browser/cloud/user_policy_signin_service_util.cc +++ b/components/policy/core/browser/cloud/user_policy_signin_service_util.cc
@@ -4,8 +4,10 @@ #include "components/policy/core/browser/cloud/user_policy_signin_service_util.h" -#include "components/signin/public/base/consent_level.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/prefs/pref_service.h" #include "components/signin/public/identity_manager/identity_manager.h" +#include "net/base/network_change_notifier.h" namespace policy { @@ -28,12 +30,52 @@ bool CanApplyPoliciesForSignedInUser( bool check_for_refresh_token, + signin::ConsentLevel consent_level, signin::IdentityManager* identity_manager) { return ( check_for_refresh_token - ? identity_manager->HasPrimaryAccountWithRefreshToken( - signin::ConsentLevel::kSignin) - : identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)); + ? identity_manager->HasPrimaryAccountWithRefreshToken(consent_level) + : identity_manager->HasPrimaryAccount(consent_level)); } +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) + +base::Time GetLastPolicyCheckTimeFromPrefs(PrefService* prefs) { + return base::Time::FromInternalValue( + prefs->GetInt64(policy::policy_prefs::kLastPolicyCheckTime)); +} + +void UpdateLastPolicyCheckTimeInPrefs(PrefService* prefs) { + // Persist the current time as the last policy registration attempt time. + prefs->SetInt64(policy_prefs::kLastPolicyCheckTime, + base::Time::Now().ToInternalValue()); +} + +base::TimeDelta GetTryRegistrationDelayFromPrefs(PrefService* prefs) { + net::NetworkChangeNotifier::ConnectionType connection_type = + net::NetworkChangeNotifier::GetConnectionType(); + base::TimeDelta retry_delay = base::Days(3); + if (connection_type == net::NetworkChangeNotifier::CONNECTION_ETHERNET || + connection_type == net::NetworkChangeNotifier::CONNECTION_WIFI) { + retry_delay = base::Days(1); + } + + base::Time last_check_time = GetLastPolicyCheckTimeFromPrefs(prefs); + base::Time now = base::Time::Now(); + base::Time next_check_time = last_check_time + retry_delay; + + // If the current timestamp (|now|) falls between |last_check_time| and + // |next_check_time|, return the necessary |try_registration_delay| to reach + // |next_check_time| from current time (|now|)). Returns the default + // |try_registration_delay| otherwise to perform the overdue registration + // asap. + base::TimeDelta try_registration_delay = base::Seconds(5); + if (now > last_check_time && now < next_check_time) + try_registration_delay = next_check_time - now; + + return try_registration_delay; +} + +#endif + } // namespace policy
diff --git a/components/policy/core/browser/cloud/user_policy_signin_service_util.h b/components/policy/core/browser/cloud/user_policy_signin_service_util.h index a3e22a9..4432bbc 100644 --- a/components/policy/core/browser/cloud/user_policy_signin_service_util.h +++ b/components/policy/core/browser/cloud/user_policy_signin_service_util.h
@@ -5,9 +5,14 @@ #ifndef COMPONENTS_POLICY_CORE_BROWSER_CLOUD_USER_POLICY_SIGNIN_SERVICE_UTIL_H_ #define COMPONENTS_POLICY_CORE_BROWSER_CLOUD_USER_POLICY_SIGNIN_SERVICE_UTIL_H_ +#include "base/time/time.h" +#include "build/build_config.h" #include "components/policy/policy_export.h" +#include "components/signin/public/base/consent_level.h" #include "components/signin/public/identity_manager/primary_account_change_event.h" +class PrefService; + namespace signin { class IdentityManager; } // namespace signin @@ -29,8 +34,25 @@ // Returns true if policies can be applied for the signed in user. POLICY_EXPORT bool CanApplyPoliciesForSignedInUser( bool check_for_refresh_token, + signin::ConsentLevel consent_level, signin::IdentityManager* identity_manager); +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) + +// Gets the timestamp representing the last time the registration was done. +POLICY_EXPORT base::Time GetLastPolicyCheckTimeFromPrefs(PrefService* prefs); + +// Updates the timestamp representing the last time the registration was done +// with the current time. +POLICY_EXPORT void UpdateLastPolicyCheckTimeInPrefs(PrefService* prefs); + +// Gets the delay between each registration try. Used for mobile to throttle +// network calls. +POLICY_EXPORT base::TimeDelta GetTryRegistrationDelayFromPrefs( + PrefService* prefs); + +#endif + } // namespace policy #endif // COMPONENTS_POLICY_CORE_BROWSER_CLOUD_USER_POLICY_SIGNIN_SERVICE_UTIL_H_
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.cc b/components/policy/core/common/cloud/user_cloud_policy_manager.cc index 29aae51..a9ef8c1 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_manager.cc +++ b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/task/sequenced_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "components/account_id/account_id.h" @@ -24,6 +25,19 @@ namespace em = enterprise_management; +namespace { + +// Directory inside the profile directory where policy-related resources are +// stored. +const base::FilePath::CharType kPolicy[] = FILE_PATH_LITERAL("Policy"); + +// Directory under `kPolicy`, in the user's profile dir, where policy for +// components is cached. +const base::FilePath::CharType kComponentsDir[] = + FILE_PATH_LITERAL("Components"); + +} // namespace + namespace policy { UserCloudPolicyManager::UserCloudPolicyManager( @@ -43,6 +57,28 @@ UserCloudPolicyManager::~UserCloudPolicyManager() {} +std::unique_ptr<UserCloudPolicyManager> UserCloudPolicyManager::Create( + const base::FilePath& profile_path, + SchemaRegistry* schema_registry, + bool force_immediate_load, + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, + network::NetworkConnectionTrackerGetter network_connection_tracker_getter) { + std::unique_ptr<UserCloudPolicyStore> store = + UserCloudPolicyStore::Create(profile_path, background_task_runner); + if (force_immediate_load) + store->LoadImmediately(); + + const base::FilePath component_policy_cache_dir = + profile_path.Append(kPolicy).Append(kComponentsDir); + + auto policy_manager = std::make_unique<UserCloudPolicyManager>( + std::move(store), component_policy_cache_dir, + std::unique_ptr<CloudExternalDataManager>(), + base::ThreadTaskRunnerHandle::Get(), network_connection_tracker_getter); + policy_manager->Init(schema_registry); + return policy_manager; +} + void UserCloudPolicyManager::Shutdown() { if (external_data_manager_) external_data_manager_->Disconnect();
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.h b/components/policy/core/common/cloud/user_cloud_policy_manager.h index 95705d9a..aacdb5d 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_manager.h +++ b/components/policy/core/common/cloud/user_cloud_policy_manager.h
@@ -25,6 +25,8 @@ class SharedURLLoaderFactory; } +class SchemaRegistry; + namespace policy { class CloudExternalDataManager; @@ -46,6 +48,14 @@ UserCloudPolicyManager& operator=(const UserCloudPolicyManager&) = delete; ~UserCloudPolicyManager() override; + static std::unique_ptr<UserCloudPolicyManager> Create( + const base::FilePath& profile_path, + SchemaRegistry* schema_registry, + bool force_immediate_load, + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, + network::NetworkConnectionTrackerGetter + network_connection_tracker_getter); + // ConfigurationPolicyProvider overrides: void Shutdown() override;
diff --git a/components/policy/core/common/policy_pref_names.cc b/components/policy/core/common/policy_pref_names.cc index 3739679..1ec350d3 100644 --- a/components/policy/core/common/policy_pref_names.cc +++ b/components/policy/core/common/policy_pref_names.cc
@@ -98,5 +98,13 @@ // Boolean policy to force WebSQL to be enabled. const char kWebSQLAccess[] = "policy.web_sql_access"; +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) +// Last time that a check for cloud policy management was done. This time is +// recorded on Android and iOS so that retries aren't attempted on every +// startup. Instead the cloud policy registration is retried at least 1 or 3 +// days later. +const char kLastPolicyCheckTime[] = "policy.last_policy_check_time"; +#endif + } // namespace policy_prefs } // namespace policy
diff --git a/components/policy/core/common/policy_pref_names.h b/components/policy/core/common/policy_pref_names.h index 6d02d1e..9439c5b 100644 --- a/components/policy/core/common/policy_pref_names.h +++ b/components/policy/core/common/policy_pref_names.h
@@ -38,6 +38,9 @@ #endif // BUILDFLAG(IS_ANDROID) POLICY_EXPORT extern const char kIsolatedAppsDeveloperModeAllowed[]; POLICY_EXPORT extern const char kWebSQLAccess[]; +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) +POLICY_EXPORT extern const char kLastPolicyCheckTime[]; +#endif } // namespace policy_prefs } // namespace policy
diff --git a/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc index 153438d..d4ac1cde9 100644 --- a/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc +++ b/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc
@@ -188,9 +188,10 @@ try_token_fetch, nullptr), cache_manager_( - std::make_unique<VerdictCacheManager>(nullptr, + std::make_unique<VerdictCacheManager>(/*history_service=*/nullptr, content_setting_map.get(), - pref_service)) { + pref_service, + /*sync_observer=*/nullptr)) { cache_manager_->StopCleanUpTimerForTesting(); } TestPasswordProtectionService(const TestPasswordProtectionService&) = delete;
diff --git a/components/safe_browsing/core/browser/BUILD.gn b/components/safe_browsing/core/browser/BUILD.gn index c63df98..d931494 100644 --- a/components/safe_browsing/core/browser/BUILD.gn +++ b/components/safe_browsing/core/browser/BUILD.gn
@@ -21,6 +21,7 @@ "//base", "//components/keyed_service/core", "//components/prefs", + "//components/safe_browsing/core/browser:sync_observer", "//components/safe_browsing/core/browser:token_fetcher", "//components/safe_browsing/core/browser/db:database_manager", "//components/safe_browsing/core/browser/db:hit_report", @@ -91,6 +92,7 @@ "//components/keyed_service/core:core", "//components/password_manager/core/browser:browser", "//components/prefs", + "//components/safe_browsing/core/browser:sync_observer", "//components/safe_browsing/core/browser/db:v4_protocol_manager_util", "//components/safe_browsing/core/common", "//components/safe_browsing/core/common/proto:csd_proto", @@ -108,6 +110,7 @@ "//base", "//base/test:test_support", "//components/content_settings/core/browser", + "//components/safe_browsing/core/browser:sync_observer", "//components/safe_browsing/core/common:safe_browsing_prefs", "//components/safe_browsing/core/common/proto:csd_proto", "//components/safe_browsing/core/common/proto:realtimeapi_proto",
diff --git a/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc b/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc index ec6ea3b3..323d521 100644 --- a/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc +++ b/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
@@ -104,7 +104,9 @@ &test_pref_service_, false /* is_off_the_record */, false /* store_last_modified */, false /* restore_session */); cache_manager_ = std::make_unique<VerdictCacheManager>( - nullptr, content_setting_map_.get(), &test_pref_service_); + /*history_service=*/nullptr, content_setting_map_.get(), + &test_pref_service_, + /*sync_observer=*/nullptr); referrer_chain_provider_ = std::make_unique<MockReferrerChainProvider>(); auto token_fetcher = std::make_unique<TestSafeBrowsingTokenFetcher>();
diff --git a/components/safe_browsing/core/browser/verdict_cache_manager.cc b/components/safe_browsing/core/browser/verdict_cache_manager.cc index 9949c893..7ee2f1b 100644 --- a/components/safe_browsing/core/browser/verdict_cache_manager.cc +++ b/components/safe_browsing/core/browser/verdict_cache_manager.cc
@@ -387,11 +387,13 @@ VerdictCacheManager::VerdictCacheManager( history::HistoryService* history_service, scoped_refptr<HostContentSettingsMap> content_settings, - PrefService* pref_service) + PrefService* pref_service, + std::unique_ptr<SafeBrowsingSyncObserver> sync_observer) : stored_verdict_count_password_on_focus_(absl::nullopt), stored_verdict_count_password_entry_(absl::nullopt), stored_verdict_count_real_time_url_check_(absl::nullopt), - content_settings_(content_settings) { + content_settings_(content_settings), + sync_observer_(std::move(sync_observer)) { if (history_service) history_service_observation_.Observe(history_service); if (!content_settings->IsOffTheRecord()) { @@ -411,6 +413,12 @@ weak_factory_.GetWeakPtr(), ClearReason::kSafeBrowsingStateChanged)); } + // sync_observer_ can be null in some embedders that don't support sync. + if (sync_observer_) { + sync_observer_->ObserveSyncStateChanged(base::BindRepeating( + &VerdictCacheManager::CleanUpAllPageLoadTokens, + weak_factory_.GetWeakPtr(), ClearReason::kSyncStateChanged)); + } CacheArtificialRealTimeUrlVerdict(); CacheArtificialPhishGuardVerdict(); } @@ -419,6 +427,7 @@ CleanUpExpiredVerdicts(); history_service_observation_.Reset(); pref_change_registrar_.RemoveAll(); + sync_observer_.reset(); weak_factory_.InvalidateWeakPtrs(); }
diff --git a/components/safe_browsing/core/browser/verdict_cache_manager.h b/components/safe_browsing/core/browser/verdict_cache_manager.h index 7e630766..1a7bda2 100644 --- a/components/safe_browsing/core/browser/verdict_cache_manager.h +++ b/components/safe_browsing/core/browser/verdict_cache_manager.h
@@ -18,6 +18,7 @@ #include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/browser/safe_browsing_sync_observer.h" #include "components/safe_browsing/core/common/proto/csd.pb.h" #include "components/safe_browsing/core/common/proto/realtimeapi.pb.h" #include "url/gurl.h" @@ -35,7 +36,8 @@ public: VerdictCacheManager(history::HistoryService* history_service, scoped_refptr<HostContentSettingsMap> content_settings, - PrefService* pref_service); + PrefService* pref_service, + std::unique_ptr<SafeBrowsingSyncObserver> sync_observer); VerdictCacheManager(const VerdictCacheManager&) = delete; VerdictCacheManager& operator=(const VerdictCacheManager&) = delete; VerdictCacheManager(VerdictCacheManager&&) = delete; @@ -133,8 +135,9 @@ enum class ClearReason { kSafeBrowsingStateChanged = 0, kCookiesDeleted = 1, + kSyncStateChanged = 2, - kMaxValue = kCookiesDeleted + kMaxValue = kSyncStateChanged }; void ScheduleNextCleanUpAfterInterval(base::TimeDelta interval); @@ -198,6 +201,8 @@ PrefChangeRegistrar pref_change_registrar_; + std::unique_ptr<SafeBrowsingSyncObserver> sync_observer_; + base::WeakPtrFactory<VerdictCacheManager> weak_factory_{this}; static bool has_artificial_unsafe_url_;
diff --git a/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc b/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc index 1601da81..b8e1b1f 100644 --- a/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc +++ b/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/task_environment.h" #include "base/values.h" #include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/safe_browsing/core/browser/safe_browsing_sync_observer.h" #include "components/safe_browsing/core/common/proto/csd.pb.h" #include "components/safe_browsing/core/common/proto/realtimeapi.pb.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" @@ -18,6 +19,27 @@ namespace safe_browsing { +namespace { + +class MockSafeBrowsingSyncObserver : public SafeBrowsingSyncObserver { + public: + MockSafeBrowsingSyncObserver() : SafeBrowsingSyncObserver() {} + + ~MockSafeBrowsingSyncObserver() override = default; + + void ObserveSyncStateChanged( + SafeBrowsingSyncObserver::Callback callback) override { + callback_ = std::move(callback); + } + + void OnSyncStateChanged() { callback_.Run(); } + + private: + Callback callback_; +}; + +} // namespace + class VerdictCacheManagerTest : public ::testing::Test { public: VerdictCacheManagerTest() {} @@ -31,8 +53,11 @@ content_setting_map_ = new HostContentSettingsMap( &test_pref_service_, false /* is_off_the_record */, false /* store_last_modified */, false /* restore_session */); + auto sync_observer = std::make_unique<MockSafeBrowsingSyncObserver>(); + raw_sync_observer_ = sync_observer.get(); cache_manager_ = std::make_unique<VerdictCacheManager>( - nullptr, content_setting_map_.get(), &test_pref_service_); + nullptr, content_setting_map_.get(), &test_pref_service_, + std::move(sync_observer)); } void TearDown() override { @@ -91,6 +116,7 @@ base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; sync_preferences::TestingPrefServiceSyncable test_pref_service_; + raw_ptr<MockSafeBrowsingSyncObserver> raw_sync_observer_ = nullptr; }; TEST_F(VerdictCacheManagerTest, TestCanRetrieveCachedVerdict) { @@ -821,4 +847,17 @@ ASSERT_FALSE(token.has_token_value()); } +TEST_F(VerdictCacheManagerTest, TestClearTokenOnSyncStateChanged) { + GURL url("https://www.example.com/path"); + cache_manager_->CreatePageLoadToken(url); + ChromeUserPopulation::PageLoadToken token = + cache_manager_->GetPageLoadToken(url); + ASSERT_TRUE(token.has_token_value()); + + raw_sync_observer_->OnSyncStateChanged(); + token = cache_manager_->GetPageLoadToken(url); + // Token is not found because the sync state has changed. + ASSERT_FALSE(token.has_token_value()); +} + } // namespace safe_browsing
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc index 1431a87..988981b 100644 --- a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc +++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -151,8 +151,7 @@ std::make_unique<SegmentSelectorImpl>( segment_info_database_.get(), signal_storage_config_.get(), segmentation_result_prefs_.get(), config.get(), clock, - platform_options_, default_model_manager_.get(), - model_execution_manager_.get()); + platform_options_, default_model_manager_.get()); } proxy_ = std::make_unique<ServiceProxyImpl>(segment_info_database_.get(), @@ -288,6 +287,10 @@ kDatabaseMaintenanceDelay); proxy_->SetModelExecutionScheduler(model_execution_scheduler_.get()); + + for (auto& selector : segment_selectors_) { + selector.second->OnPlatformInitialized(model_execution_manager_.get()); + } } void SegmentationPlatformServiceImpl::OnSegmentationModelUpdated(
diff --git a/components/segmentation_platform/internal/selection/segment_result_provider.cc b/components/segmentation_platform/internal/selection/segment_result_provider.cc index c20a84e..8d3d0bb 100644 --- a/components/segmentation_platform/internal/selection/segment_result_provider.cc +++ b/components/segmentation_platform/internal/selection/segment_result_provider.cc
@@ -177,6 +177,9 @@ DefaultModelManager::SegmentInfoList available_segments) { if (!request_state->default_provider || !request_state->default_provider->ModelAvailable()) { + VLOG(1) << __func__ << ": segment=" + << OptimizationTarget_Name(request_state->segment_id) + << " default provider not available"; PostResultCallback(std::move(request_state), std::make_unique<SegmentResult>(existing_state)); return; @@ -194,6 +197,9 @@ } if (!default_segment_info) { + VLOG(1) << __func__ << ": segment=" + << OptimizationTarget_Name(request_state->segment_id) + << " default segment info not available"; PostResultCallback(std::move(request_state), std::make_unique<SegmentResult>( ResultState::kDefaultModelMetadataMissing)); @@ -205,6 +211,9 @@ metadata_utils::ValidateMetadata(default_segment_info->model_metadata())); if (!signal_storage_config_->MeetsSignalCollectionRequirement( default_segment_info->model_metadata())) { + VLOG(1) << __func__ << ": segment=" + << OptimizationTarget_Name(request_state->segment_id) + << " signal collection not met"; PostResultCallback(std::move(request_state), std::make_unique<SegmentResult>( ResultState::kDefaultModelSignalNotCollected));
diff --git a/components/segmentation_platform/internal/selection/segment_selector.h b/components/segmentation_platform/internal/selection/segment_selector.h index af20d2a..adf0ebe9 100644 --- a/components/segmentation_platform/internal/selection/segment_selector.h +++ b/components/segmentation_platform/internal/selection/segment_selector.h
@@ -15,6 +15,7 @@ namespace segmentation_platform { struct SegmentSelectionResult; +class ModelExecutionManager; // Central class for segment selection that can be used by clients to find the // best selected segment. Listens for model execution events, on which it @@ -28,6 +29,10 @@ using SegmentSelectionCallback = base::OnceCallback<void(const SegmentSelectionResult&)>; + // Called when segmentation platform is initialized. + virtual void OnPlatformInitialized( + ModelExecutionManager* execution_manager) = 0; + // Client API. Returns the selected segment from the last session // asynchronously. If none, returns empty result. virtual void GetSelectedSegment(SegmentSelectionCallback callback) = 0;
diff --git a/components/segmentation_platform/internal/selection/segment_selector_impl.cc b/components/segmentation_platform/internal/selection/segment_selector_impl.cc index c815c12..2ffef15 100644 --- a/components/segmentation_platform/internal/selection/segment_selector_impl.cc +++ b/components/segmentation_platform/internal/selection/segment_selector_impl.cc
@@ -67,17 +67,10 @@ const Config* config, base::Clock* clock, const PlatformOptions& platform_options, - DefaultModelManager* default_model_manager, - ModelExecutionManager* execution_manager) - : segment_result_provider_(SegmentResultProvider::Create( - segment_database, - signal_storage_config, - default_model_manager, - execution_manager, - clock, - platform_options.force_refresh_results)), - segment_database_(segment_database), + DefaultModelManager* default_model_manager) + : segment_database_(segment_database), signal_storage_config_(signal_storage_config), + default_model_manager_(default_model_manager), result_prefs_(result_prefs), config_(config), clock_(clock), @@ -100,6 +93,16 @@ SegmentSelectorImpl::~SegmentSelectorImpl() = default; +void SegmentSelectorImpl::OnPlatformInitialized( + ModelExecutionManager* execution_manager) { + segment_result_provider_ = SegmentResultProvider::Create( + segment_database_, signal_storage_config_, default_model_manager_, + execution_manager, clock_, platform_options_.force_refresh_results); + if (CanComputeSegmentSelection()) { + GetRankForNextSegment(std::make_unique<SegmentRanks>()); + } +} + void SegmentSelectorImpl::GetSelectedSegment( SegmentSelectionCallback callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -113,6 +116,8 @@ void SegmentSelectorImpl::OnModelExecutionCompleted( OptimizationTarget segment_id) { + DCHECK(segment_result_provider_); + // If the |segment_id| is not in config, then skip any updates early. if (!base::Contains(config_->segment_ids, segment_id)) return;
diff --git a/components/segmentation_platform/internal/selection/segment_selector_impl.h b/components/segmentation_platform/internal/selection/segment_selector_impl.h index c7ffe4bc..be49dafe 100644 --- a/components/segmentation_platform/internal/selection/segment_selector_impl.h +++ b/components/segmentation_platform/internal/selection/segment_selector_impl.h
@@ -34,12 +34,12 @@ const Config* config, base::Clock* clock, const PlatformOptions& platform_options, - DefaultModelManager* default_model_manager, - ModelExecutionManager* execution_manager); + DefaultModelManager* default_model_manager); ~SegmentSelectorImpl() override; // SegmentSelector overrides. + void OnPlatformInitialized(ModelExecutionManager* execution_manager) override; void GetSelectedSegment(SegmentSelectionCallback callback) override; SegmentSelectionResult GetCachedSegmentResult() override; @@ -80,19 +80,22 @@ std::unique_ptr<SegmentResultProvider> segment_result_provider_; // The database storing metadata and results. - raw_ptr<SegmentInfoDatabase> segment_database_; + const raw_ptr<SegmentInfoDatabase> segment_database_; // The database to determine whether the signal storage requirements are met. - raw_ptr<SignalStorageConfig> signal_storage_config_; + const raw_ptr<SignalStorageConfig> signal_storage_config_; + + // The default model manager is used for the default model fallbacks. + const raw_ptr<DefaultModelManager> default_model_manager_; // Helper class to read/write results to the prefs. - raw_ptr<SegmentationResultPrefs> result_prefs_; + const raw_ptr<SegmentationResultPrefs> result_prefs_; // The config for providing configuration params. - raw_ptr<const Config> config_; + const raw_ptr<const Config> config_; // The time provider. - raw_ptr<base::Clock> clock_; + const raw_ptr<base::Clock> clock_; const PlatformOptions platform_options_;
diff --git a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc index 5c015e51..7046fa1 100644 --- a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc +++ b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
@@ -76,7 +76,8 @@ segment_selector_ = std::make_unique<SegmentSelectorImpl>( segment_database_.get(), &signal_storage_config_, prefs_.get(), &config_, &clock_, PlatformOptions::CreateDefault(), - default_manager_.get(), nullptr); + default_manager_.get()); + segment_selector_->OnPlatformInitialized(nullptr); } void GetSelectedSegment(const SegmentSelectionResult& expected) { @@ -307,8 +308,8 @@ // Construct a segment selector. It should read result from last session. segment_selector_ = std::make_unique<SegmentSelectorImpl>( segment_database_.get(), &signal_storage_config_, prefs_.get(), &config_, - &clock_, PlatformOptions::CreateDefault(), default_manager_.get(), - nullptr); + &clock_, PlatformOptions::CreateDefault(), default_manager_.get()); + segment_selector_->OnPlatformInitialized(nullptr); SegmentSelectionResult result; result.segment = segment_id0;
diff --git a/components/segmentation_platform/internal/service_proxy_impl_unittest.cc b/components/segmentation_platform/internal/service_proxy_impl_unittest.cc index e501408..2136f11 100644 --- a/components/segmentation_platform/internal/service_proxy_impl_unittest.cc +++ b/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
@@ -69,7 +69,6 @@ config, nullptr, PlatformOptions::CreateDefault(), - nullptr, nullptr) {} ~FakeSegmentSelectorImpl() override = default;
diff --git a/components/test/data/web_package/generate-test-wbns.sh b/components/test/data/web_package/generate-test-wbns.sh index e51da02..b969084 100755 --- a/components/test/data/web_package/generate-test-wbns.sh +++ b/components/test/data/web_package/generate-test-wbns.sh
@@ -36,10 +36,10 @@ -o 24_responses.wbn sign-bundle \ - -i hello_b1.wbn \ + -i hello_b2.wbn \ -certificate $sxg_test_data_dir/test.example.org.public.pem.cbor \ -privateKey $sxg_test_data_dir/prime256v1.key \ -date $signature_date \ -expire 168h \ -validityUrl https://test.example.org/resource.validity.msg \ - -o hello_signed_b1.wbn + -o hello_signed.wbn
diff --git a/components/test/data/web_package/hello_signed.wbn b/components/test/data/web_package/hello_signed.wbn index 8f1abaa..9970452 100644 --- a/components/test/data/web_package/hello_signed.wbn +++ b/components/test/data/web_package/hello_signed.wbn Binary files differ
diff --git a/components/test/data/web_package/hello_signed_b1.wbn b/components/test/data/web_package/hello_signed_b1.wbn deleted file mode 100644 index c820630d..0000000 --- a/components/test/data/web_package/hello_signed_b1.wbn +++ /dev/null Binary files differ
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn index 5929ea1..955128a 100644 --- a/components/vector_icons/BUILD.gn +++ b/components/vector_icons/BUILD.gn
@@ -64,6 +64,7 @@ "https_valid_arrow.icon", "info_outline.icon", "insert_drive_file_outline.icon", + "keyboard.icon", "launch.icon", "lightbulb_outline.icon", "live_caption_off.icon",
diff --git a/ash/resources/vector_icons/keyboard.icon b/components/vector_icons/keyboard.icon similarity index 100% rename from ash/resources/vector_icons/keyboard.icon rename to components/vector_icons/keyboard.icon
diff --git a/components/viz/service/display_embedder/skia_output_device.h b/components/viz/service/display_embedder/skia_output_device.h index 0473071..b8b6aa7 100644 --- a/components/viz/service/display_embedder/skia_output_device.h +++ b/components/viz/service/display_embedder/skia_output_device.h
@@ -21,7 +21,7 @@ #include "gpu/command_buffer/common/swap_buffers_complete_params.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkRefCnt.h" -#include "third_party/skia/src/gpu/GrSemaphore.h" +#include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "ui/gfx/swap_result.h" class GrDirectContext;
diff --git a/components/web_package/mojom/web_bundle_parser.mojom b/components/web_package/mojom/web_bundle_parser.mojom index f50d069..98540e21 100644 --- a/components/web_package/mojom/web_bundle_parser.mojom +++ b/components/web_package/mojom/web_bundle_parser.mojom
@@ -54,7 +54,6 @@ struct BundleMetadataParseError { BundleParseErrorType type; - url.mojom.Url fallback_url; string message; }; @@ -67,8 +66,7 @@ struct BundleMetadata { BundleFormatVersion version; url.mojom.Url primary_url; - map<url.mojom.Url, BundleIndexValue> requests; - url.mojom.Url manifest_url; + map<url.mojom.Url, BundleResponseLocation> requests; array<AugmentedCertificate> authorities; array<VouchedSubset> vouched_subsets; }; @@ -80,13 +78,6 @@ kB2, // Corresponds to draft-02 }; -// Corresponds to the value type of "index" in the spec CDDL. -// https://wpack-wg.github.io/bundled-responses/draft-ietf-wpack-bundled-responses.html#name-the-index-section -struct BundleIndexValue { - string variants_value; - array<BundleResponseLocation> response_locations; -}; - // Offset (within the webbundle file) and length of a response. struct BundleResponseLocation { uint64 offset;
diff --git a/components/web_package/web_bundle_parser.cc b/components/web_package/web_bundle_parser.cc index 09d0044..aae4a15 100644 --- a/components/web_package/web_bundle_parser.cc +++ b/components/web_package/web_bundle_parser.cc
@@ -48,26 +48,16 @@ constexpr uint64_t kInitialBufferSizeForResponse = 4096; // CBOR of the magic string "🌐📦". -// MetadataParser::ParseMagicBytes() check the first byte (86 or 85) and this. +// MetadataParser::ParseMagicBytes() checks the first byte (0x85) and this. // // The first 10 bytes of the web bundle format are: -// 86 or 85 -- Array of length 6 (b1) or 5(b2) +// 85 -- Array of length 5 // 48 -- Byte string of length 8 // F0 9F 8C 90 F0 9F 93 A6 -- "🌐📦" in UTF-8 -// Note: The length of the top level array is 6 in version b1 (magic, version, -// primary, section-lengths, sections, length), and 5 in version b2 (magic, -// version, section-lengths, sections, length). const uint8_t kBundleMagicBytes[] = { 0x48, 0xF0, 0x9F, 0x8C, 0x90, 0xF0, 0x9F, 0x93, 0xA6, }; -// CBOR of the version string "b1\0\0". -// 44 -- Byte string of length 4 -// 62 31 00 00 -- "b1\0\0" -const uint8_t kVersionB1MagicBytes[] = { - 0x44, 0x62, 0x31, 0x00, 0x00, -}; - // CBOR of the version string "b2\0\0". // 44 -- Byte string of length 4 // 62 32 00 00 -- "b2\0\0" @@ -78,7 +68,6 @@ // Section names. constexpr char kCriticalSection[] = "critical"; constexpr char kIndexSection[] = "index"; -constexpr char kManifestSection[] = "manifest"; constexpr char kPrimarySection[] = "primary"; constexpr char kResponsesSection[] = "responses"; constexpr char kSignaturesSection[] = "signatures"; @@ -98,8 +87,7 @@ bool IsMetadataSection(const std::string& name) { return (name == kCriticalSection || name == kIndexSection || - name == kManifestSection || name == kPrimarySection || - name == kSignaturesSection); + name == kPrimarySection || name == kSignaturesSection); } // Parses a `section-lengths` CBOR item. @@ -408,11 +396,11 @@ } void ReadMagicBytes(const uint64_t offset_in_stream) { - // First, we will parse one byte at the very beginning to determine the size - // of the CBOR top level array (hence the "1+"), then `magic` and `version` - // bytes. - const uint64_t length = - 1 + sizeof(kBundleMagicBytes) + sizeof(kVersionB1MagicBytes); + // First, we will parse the CBOR header of the top level array (1-byte), + // `magic`, `version`, and the CBOR header of `section-lengths`. + const uint64_t length = 1 + sizeof(kBundleMagicBytes) + + sizeof(kVersionB2MagicBytes) + + kMaxCBORItemHeaderSize; data_source_->Read( offset_in_stream, length, base::BindOnce(&MetadataParser::ParseMagicBytes, @@ -429,26 +417,20 @@ InputReader input(*data); - // Read the first byte denoting a CBOR array size. For bundles of b1 - // version, it will be equal to 0x86 (6), as there's a primary url - // present in the top level structure. For newer bundles it must be - // equal to 0x85 (5). + // Read the first byte denoting a CBOR array size. It must be equal to 0x85 + // (5). const auto array_size = input.ReadByte(); if (!array_size) { RunErrorCallbackAndDestroy("Missing CBOR array size byte."); return; } - if (*array_size != 0x86 && *array_size != 0x85) { + if (*array_size != 0x85) { RunErrorCallbackAndDestroy( "Wrong CBOR array size of the top-level structure"); return; } - if (array_size == 0x86) { - bundle_version_is_b1_ = true; - } - // Check the magic bytes "48 F0 9F 8C 90 F0 9F 93 A6". const auto magic = input.ReadBytes(sizeof(kBundleMagicBytes)); if (!magic || @@ -459,113 +441,20 @@ } // Let version be the result of reading 5 bytes from stream. - const auto version = input.ReadBytes(sizeof(kVersionB1MagicBytes)); + const auto version = input.ReadBytes(sizeof(kVersionB2MagicBytes)); if (!version) { RunErrorCallbackAndDestroy("Cannot read version bytes."); return; } - offset_in_stream += input.CurrentOffset(); - if (bundle_version_is_b1_) { - if (!std::equal(version->begin(), version->end(), - std::begin(kVersionB1MagicBytes), - std::end(kVersionB1MagicBytes))) { - RunErrorCallbackAndDestroy( - "Version error: bundle format does not correspond to the specifed " - "version. Currently supported version are: 'b1' and 'b2'", - mojom::BundleParseErrorType::kVersionError); - return; - } - data_source_->Read( - offset_in_stream, kMaxCBORItemHeaderSize, - base::BindOnce(&MetadataParser::ReadCBORHeaderOfPrimaryURL, - weak_factory_.GetWeakPtr(), offset_in_stream)); - } else { - // The only other version we support is "b2", in case of a mismatch we - // should return with "version error" later. - if (!std::equal(version->begin(), version->end(), - std::begin(kVersionB2MagicBytes), - std::end(kVersionB2MagicBytes))) { - RunErrorCallbackAndDestroy( - "Version error: bundle format does not correspond to the specifed " - "version. Currently supported version are: 'b1' and 'b2'", - mojom::BundleParseErrorType::kVersionError); - return; - } - ReadBundleHeader(offset_in_stream); - } - } - - void ReadCBORHeaderOfPrimaryURL( - uint64_t offset_in_stream, - const absl::optional<std::vector<uint8_t>>& data) { - DCHECK(bundle_version_is_b1_); - if (!data) { - RunErrorCallbackAndDestroy("Error reading bundle header."); + if (!std::equal(version->begin(), version->end(), + std::begin(kVersionB2MagicBytes), + std::end(kVersionB2MagicBytes))) { + RunErrorCallbackAndDestroy( + "Version error: bundle format does not correspond to the specifed " + "version. Currently supported version is: 'b2'", + mojom::BundleParseErrorType::kVersionError); return; } - InputReader input(*data); - - const auto url_length = input.ReadCBORHeader(CBORType::kTextString); - if (!url_length) { - RunErrorCallbackAndDestroy("Cannot parse the size of primary URL."); - return; - } - - offset_in_stream += input.CurrentOffset(); - data_source_->Read(offset_in_stream, *url_length, - base::BindOnce(&MetadataParser::ParsePrimaryURL, - weak_factory_.GetWeakPtr(), *url_length, - offset_in_stream)); - } - - void ParsePrimaryURL(uint64_t url_length, - uint64_t offset_in_stream, - const absl::optional<std::vector<uint8_t>>& data) { - DCHECK(bundle_version_is_b1_); - if (!data) { - RunErrorCallbackAndDestroy("Error reading bundle header."); - return; - } - InputReader input(*data); - - const auto primary_url_string = input.ReadString(url_length); - if (!primary_url_string) { - RunErrorCallbackAndDestroy("Cannot read primary URL."); - return; - } - - // TODO(crbug.com/966753): Revisit URL requirements here once - // https://github.com/WICG/webpackage/issues/469 is resolved. - GURL primary_url = ParseExchangeURL(*primary_url_string, base_url_); - if (!primary_url.is_valid()) { - RunErrorCallbackAndDestroy("Cannot parse primary URL."); - return; - } - - primary_url_ = std::move(primary_url); - - ReadBundleHeader(input.CurrentOffset() + offset_in_stream); - } - - void ReadBundleHeader(uint64_t offset_in_stream) { - // In the next step, we will parse the content of `section-lengths`, - // and the CBOR header of `sections`. - const uint64_t length = - kMaxSectionLengthsCBORSize + kMaxCBORItemHeaderSize * 2; - - data_source_->Read( - offset_in_stream, length, - base::BindOnce(&MetadataParser::ParseBundleHeader, - weak_factory_.GetWeakPtr(), offset_in_stream)); - } - - void ParseBundleHeader(uint64_t offset_in_stream, - const absl::optional<std::vector<uint8_t>>& data) { - if (!data) { - RunErrorCallbackAndDestroy("Error reading bundle header."); - return; - } - InputReader input(*data); const auto section_lengths_length = input.ReadCBORHeader(CBORType::kByteString); @@ -585,6 +474,27 @@ return; } + // In the next step, we will parse the content of `section-lengths`, + // and the CBOR header of `sections`. + const uint64_t length = *section_lengths_length + kMaxCBORItemHeaderSize; + + offset_in_stream += input.CurrentOffset(); + data_source_->Read( + offset_in_stream, length, + base::BindOnce(&MetadataParser::ParseBundleHeader, + weak_factory_.GetWeakPtr(), offset_in_stream, + *section_lengths_length)); + } + + void ParseBundleHeader(uint64_t offset_in_stream, + uint64_t section_lengths_length, + const absl::optional<std::vector<uint8_t>>& data) { + if (!data) { + RunErrorCallbackAndDestroy("Error reading bundle header."); + return; + } + InputReader input(*data); + // webbundle = [ // magic: h'F0 9F 8C 90 F0 9F 93 A6', // version: bytes .size 4, @@ -592,7 +502,7 @@ // sections: [* any ], // length: bytes .size 8, ; Big-endian number of bytes in the bundle. // ] - const auto section_lengths_bytes = input.ReadBytes(*section_lengths_length); + const auto section_lengths_bytes = input.ReadBytes(section_lengths_length); if (!section_lengths_bytes) { RunErrorCallbackAndDestroy("Cannot read section-lengths."); return; @@ -662,13 +572,7 @@ // Initialize |metadata_|. metadata_ = mojom::BundleMetadata::New(); - if (bundle_version_is_b1_) { - DCHECK(!primary_url_.is_empty()); - metadata_->primary_url = primary_url_; - metadata_->version = mojom::BundleFormatVersion::kB1; - } else { - metadata_->version = mojom::BundleFormatVersion::kB2; - } + metadata_->version = mojom::BundleFormatVersion::kB2; ReadMetadataSections(section_offsets_.begin()); } @@ -728,9 +632,6 @@ if (name == kIndexSection) { if (!ParseIndexSection(*section_value)) return; - } else if (name == kManifestSection) { - if (!ParseManifestSection(*section_value)) - return; } else if (name == kSignaturesSection) { if (!ParseSignaturesSection(*section_value)) return; @@ -748,11 +649,7 @@ } // https://www.ietf.org/archive/id/draft-ietf-wpack-bundled-responses-01.html#name-the-index-section - // For 'b1' bundles, index section has the following structure: - // index = {* whatwg-url => [ variants-value, +location-in-responses ] } - // variants-value = bstr - // location-in-responses = (offset: uint, length: uint) - // For 'b2' bundles however, it's different: + // The index section has the following structure: // index = {* whatwg-url => [ location-in-responses ] } // location-in-responses = (offset: uint, length: uint) bool ParseIndexSection(const cbor::Value& section_value) { @@ -762,7 +659,7 @@ return false; } - base::flat_map<GURL, mojom::BundleIndexValuePtr> requests; + base::flat_map<GURL, mojom::BundleResponseLocationPtr> requests; auto responses_section = section_offsets_.find(kResponsesSection); DCHECK(responses_section != section_offsets_.end()); @@ -789,103 +686,38 @@ return false; } - // To support BundleIndexValue with |variants_value| defined and without - // we first initialize it as an empty string (default value for 'b2' - // version) and then fill it with an actual value if present (in 'b1' - // bundles). - base::StringPiece variants_value = ""; - if (bundle_version_is_b1_) { - // Parse |variants_value|. - if (responses_array.empty() || !responses_array[0].is_bytestring()) { - RunErrorCallbackAndDestroy( - "Index section: the first element of responses array must be a " - "bytestring."); - return false; - } - variants_value = responses_array[0].GetBytestringAsString(); - if (variants_value.empty()) { - // When |variants_value| is an empty string, the length of responses - // must be 3 (variants-value, offset, length). - if (responses_array.size() != 3) { - RunErrorCallbackAndDestroy( - "Index section: unexpected size of responses array."); - return false; - } - } else { - // TODO(crbug.com/969596): Parse variants_value to compute the number - // of variantKeys, and check that responses_array has (2 * - // #variantKeys + 1) elements. - if (responses_array.size() < 3 || responses_array.size() % 2 != 1) { - RunErrorCallbackAndDestroy( - "Index section: unexpected size of responses array."); - return false; - } - } - } else { - if (responses_array.size() != 2) { - RunErrorCallbackAndDestroy( - "Index section: the size of a response array per URL should be " - "exactly 2 for bundles without variant support ('b2')."); - return false; - } + if (responses_array.size() != 2) { + RunErrorCallbackAndDestroy( + "Index section: the size of a response array per URL should be " + "exactly 2."); + return false; } - // Instead of constructing a map from Variant-Keys to location-in-stream, - // this implementation just returns the responses array's structure as - // a BundleIndexValue. - // When parsing a 'b1' bundle, we start the array lookup from 1, as the - // first element is |variants_value|. For 'b2' bundles and forward, we - // start from zero, as the array only consists of 2 values: offset and - // length. - std::vector<mojom::BundleResponseLocationPtr> response_locations; - for (size_t i = bundle_version_is_b1_ ? 1 : 0; i < responses_array.size(); - i += 2) { - if (!responses_array[i].is_unsigned() || - !responses_array[i + 1].is_unsigned()) { - RunErrorCallbackAndDestroy( - "Index section: offset and length values must be unsigned."); - return false; - } - uint64_t offset = responses_array[i].GetUnsigned(); - uint64_t length = responses_array[i + 1].GetUnsigned(); - - uint64_t response_end; - if (!base::CheckAdd(offset, length).AssignIfValid(&response_end) || - response_end > responses_section_length) { - RunErrorCallbackAndDestroy("Index section: response out of range."); - return false; - } - uint64_t offset_within_stream = responses_section_offset + offset; - - response_locations.push_back( - mojom::BundleResponseLocation::New(offset_within_stream, length)); + if (!responses_array[0].is_unsigned() || + !responses_array[1].is_unsigned()) { + RunErrorCallbackAndDestroy( + "Index section: offset and length values must be unsigned."); + return false; } + uint64_t offset = responses_array[0].GetUnsigned(); + uint64_t length = responses_array[1].GetUnsigned(); + + uint64_t response_end; + if (!base::CheckAdd(offset, length).AssignIfValid(&response_end) || + response_end > responses_section_length) { + RunErrorCallbackAndDestroy("Index section: response out of range."); + return false; + } + uint64_t offset_within_stream = responses_section_offset + offset; + requests.insert(std::make_pair( parsed_url, - mojom::BundleIndexValue::New(std::string(variants_value), - std::move(response_locations)))); + mojom::BundleResponseLocation::New(offset_within_stream, length))); } metadata_->requests = std::move(requests); return true; } - // https://www.ietf.org/archive/id/draft-ietf-wpack-bundled-responses-01.html#name-the-manifest-section - // manifest = whatwg-url - bool ParseManifestSection(const cbor::Value& section_value) { - if (!section_value.is_string()) { - RunErrorCallbackAndDestroy("Manifest section must be a string."); - return false; - } - GURL parsed_url = ParseExchangeURL(section_value.GetString(), base_url_); - - if (!parsed_url.is_valid()) { - RunErrorCallbackAndDestroy("Manifest URL is not a valid exchange URL."); - return false; - } - metadata_->manifest_url = std::move(parsed_url); - return true; - } - // https://github.com/WICG/webpackage/blob/main/extensions/signatures-section.md // signatures = [ // authorities: [*authority], @@ -1017,14 +849,6 @@ // https://github.com/WICG/webpackage/blob/main/extensions/primary-section.md // primary = whatwg-url bool ParsePrimarySection(const cbor::Value& section_value) { - // Check if the WebBundle version is equal to "b1", in which case this - // section should not even be parsed. - if (bundle_version_is_b1_) { - RunErrorCallbackAndDestroy( - "Primary section is present but the bundle version 'b1' does not " - "support it."); - return false; - } if (!section_value.is_string()) { RunErrorCallbackAndDestroy("Primary section must be a string."); return false; @@ -1218,7 +1042,7 @@ mojom::BundleParseErrorType error_type = mojom::BundleParseErrorType::kFormatError) { mojom::BundleMetadataParseErrorPtr err = - mojom::BundleMetadataParseError::New(error_type, primary_url_, message); + mojom::BundleMetadataParseError::New(error_type, message); std::move(callback_).Run(nullptr, std::move(err)); delete this; } @@ -1231,10 +1055,8 @@ scoped_refptr<SharedBundleDataSource> data_source_; const GURL base_url_; ParseMetadataCallback callback_; - GURL primary_url_; SectionOffsets section_offsets_; mojom::BundleMetadataPtr metadata_; - bool bundle_version_is_b1_ = false; base::WeakPtrFactory<MetadataParser> weak_factory_{this}; };
diff --git a/components/web_package/web_bundle_parser_factory_unittest.cc b/components/web_package/web_bundle_parser_factory_unittest.cc index da31e0d..680b36d9 100644 --- a/components/web_package/web_bundle_parser_factory_unittest.cc +++ b/components/web_package/web_bundle_parser_factory_unittest.cc
@@ -137,13 +137,10 @@ std::map<std::string, mojom::BundleResponsePtr> responses; for (const auto& item : metadata->requests) { - ASSERT_TRUE(item.second->variants_value.empty()); - ASSERT_EQ(item.second->response_locations.size(), 1u); base::test::TestFuture<mojom::BundleResponsePtr, mojom::BundleResponseParseErrorPtr> future; - parser->ParseResponse(item.second->response_locations[0]->offset, - item.second->response_locations[0]->length, + parser->ParseResponse(item.second->offset, item.second->length, future.GetCallback()); auto [response, error] = future.Take(); ASSERT_TRUE(response);
diff --git a/components/web_package/web_bundle_parser_fuzzer.cc b/components/web_package/web_bundle_parser_fuzzer.cc index f8bbf35..34c2389 100644 --- a/components/web_package/web_bundle_parser_fuzzer.cc +++ b/components/web_package/web_bundle_parser_fuzzer.cc
@@ -81,10 +81,8 @@ std::move(quit_loop_).Run(); return; } - for (const auto& item : metadata->requests) { - for (auto& resp_location : item.second->response_locations) - locations_.push_back(std::move(resp_location)); - } + for (auto& item : metadata->requests) + locations_.push_back(std::move(item.second)); ParseResponses(0); }
diff --git a/components/web_package/web_bundle_parser_unittest.cc b/components/web_package/web_bundle_parser_unittest.cc index 1d9299d..53b23be3 100644 --- a/components/web_package/web_bundle_parser_unittest.cc +++ b/components/web_package/web_bundle_parser_unittest.cc
@@ -107,17 +107,12 @@ return result; } -void ExpectFormatError(ParseBundleResult result, - bool should_have_fallback_url = false) { +void ExpectFormatError(ParseBundleResult result) { ASSERT_TRUE(result.second); EXPECT_EQ(result.second->type, mojom::BundleParseErrorType::kFormatError); - if (should_have_fallback_url) { - EXPECT_EQ(result.second->fallback_url, kFallbackUrl); - } } -// Finds the only response for |url|. The index entry for |url| must not have -// variants-value. +// Finds the response for |url|. mojom::BundleResponseLocationPtr FindResponse( const mojom::BundleMetadataPtr& metadata, const GURL& url) { @@ -125,12 +120,7 @@ if (item == metadata->requests.end()) return nullptr; - const mojom::BundleIndexValuePtr& index_value = item->second; - EXPECT_TRUE(index_value->variants_value.empty()); - EXPECT_EQ(index_value->response_locations.size(), 1u); - if (index_value->response_locations.empty()) - return nullptr; - return index_value->response_locations[0].Clone(); + return item->second.Clone(); } mojom::BundleResponsePtr ParseResponse( @@ -185,7 +175,6 @@ mojom::BundleMetadataParseErrorPtr error = ParseBundle(&data_source).second; ASSERT_TRUE(error); EXPECT_EQ(error->type, mojom::BundleParseErrorType::kFormatError); - EXPECT_TRUE(error->fallback_url.is_empty()); } TEST_F(WebBundleParserTest, UnknownVersion) { @@ -201,29 +190,6 @@ EXPECT_EQ(error->type, mojom::BundleParseErrorType::kVersionError); } -TEST_F(WebBundleParserTest, FallbackURLIsNotUTF8) { - WebBundleBuilder builder("https://test.example.com/\xcc", kManifestUrl, - BundleVersion::kB1, true); - std::vector<uint8_t> bundle = builder.CreateBundle(); - TestDataSource data_source(bundle); - - mojom::BundleMetadataParseErrorPtr error = ParseBundle(&data_source).second; - ASSERT_TRUE(error); - EXPECT_EQ(error->type, mojom::BundleParseErrorType::kFormatError); - EXPECT_TRUE(error->fallback_url.is_empty()); -} - -TEST_F(WebBundleParserTest, FallbackURLHasFragment) { - WebBundleBuilder builder("https://test.example.com/#fragment", kManifestUrl); - std::vector<uint8_t> bundle = builder.CreateBundle(); - TestDataSource data_source(bundle); - - mojom::BundleMetadataParseErrorPtr error = ParseBundle(&data_source).second; - ASSERT_TRUE(error); - EXPECT_EQ(error->type, mojom::BundleParseErrorType::kFormatError); - EXPECT_TRUE(error->fallback_url.is_empty()); -} - TEST_F(WebBundleParserTest, SectionLengthsTooLarge) { WebBundleBuilder builder(kFallbackUrl, kManifestUrl); std::string too_long_section_name(8192, 'x'); @@ -242,27 +208,6 @@ ExpectFormatError(ParseBundle(&data_source)); } -TEST_F(WebBundleParserTest, B1BundleSingleEntry) { - WebBundleBuilder builder(kFallbackUrl, kManifestUrl, BundleVersion::kB1); - builder.AddExchange("https://test.example.com/", - {{":status", "200"}, {"content-type", "text/plain"}}, - "payload"); - TestDataSource data_source(builder.CreateBundle()); - - mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first; - ASSERT_TRUE(metadata); - ASSERT_EQ(metadata->version, mojom::BundleFormatVersion::kB1); - ASSERT_EQ(metadata->requests.size(), 1u); - auto location = FindResponse(metadata, GURL("https://test.example.com/")); - ASSERT_TRUE(location); - auto response = ParseResponse(&data_source, location); - ASSERT_TRUE(response); - EXPECT_EQ(response->response_code, 200); - EXPECT_EQ(response->response_headers.size(), 1u); - EXPECT_EQ(response->response_headers["content-type"], "text/plain"); - EXPECT_EQ(data_source.GetPayload(response), "payload"); -} - TEST_F(WebBundleParserTest, InvalidRequestURL) { WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("", {{":status", "200"}, {"content-type", "text/plain"}}, @@ -435,35 +380,6 @@ ASSERT_TRUE(ParseResponse(&data_source, location)); } -TEST_F(WebBundleParserTest, Variants) { - WebBundleBuilder builder(kFallbackUrl, kManifestUrl, BundleVersion::kB1); - auto location1 = builder.AddResponse( - {{":status", "200"}, {"content-type", "text/html"}}, "payload1"); - auto location2 = builder.AddResponse( - {{":status", "200"}, {"content-type", "text/plain"}}, "payload2"); - builder.AddIndexEntry("https://test.example.com/", - "Accept;text/html;text/plain", {location1, location2}); - TestDataSource data_source(builder.CreateBundle()); - - mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first; - ASSERT_TRUE(metadata); - const auto& found = - metadata->requests.find(GURL("https://test.example.com/")); - ASSERT_NE(found, metadata->requests.end()); - const mojom::BundleIndexValuePtr& index_entry = found->second; - EXPECT_EQ(index_entry->variants_value, "Accept;text/html;text/plain"); - ASSERT_EQ(index_entry->response_locations.size(), 2u); - - auto response1 = - ParseResponse(&data_source, index_entry->response_locations[0]); - ASSERT_TRUE(response1); - EXPECT_EQ(data_source.GetPayload(response1), "payload1"); - auto response2 = - ParseResponse(&data_source, index_entry->response_locations[1]); - ASSERT_TRUE(response2); - EXPECT_EQ(data_source.GetPayload(response2), "payload2"); -} - TEST_F(WebBundleParserTest, EmptyIndexEntry) { WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddIndexEntry("https://test.example.com/", "", {}); @@ -472,37 +388,12 @@ ExpectFormatError(ParseBundle(&data_source)); } -TEST_F(WebBundleParserTest, EmptyIndexEntryWithVariants) { - WebBundleBuilder builder(kFallbackUrl, kManifestUrl, BundleVersion::kB1); - builder.AddIndexEntry("https://test.example.com/", - "Accept;text/html;text/plain", {}); - TestDataSource data_source(builder.CreateBundle()); - - ExpectFormatError(ParseBundle(&data_source), - /* should_have_fallback_url */ true); -} - -TEST_F(WebBundleParserTest, MultipleResponsesWithoutVariantsValue) { - WebBundleBuilder builder(kFallbackUrl, kManifestUrl, BundleVersion::kB1); - auto location1 = builder.AddResponse( - {{":status", "200"}, {"content-type", "text/html"}}, "payload1"); - auto location2 = builder.AddResponse( - {{":status", "200"}, {"content-type", "text/plain"}}, "payload2"); - builder.AddIndexEntry("https://test.example.com/", "", - {location1, location2}); - TestDataSource data_source(builder.CreateBundle()); - - ExpectFormatError(ParseBundle(&data_source), - /* should_have_fallback_url */ true); -} - TEST_F(WebBundleParserTest, AllKnownSectionInCritical) { WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); cbor::Value::ArrayValue critical_section; - critical_section.emplace_back("manifest"); critical_section.emplace_back("index"); critical_section.emplace_back("critical"); critical_section.emplace_back("responses"); @@ -526,29 +417,6 @@ ExpectFormatError(ParseBundle(&data_source)); } -TEST_F(WebBundleParserTest, NoManifest) { - WebBundleBuilder builder(kFallbackUrl, std::string()); - builder.AddExchange("https://test.example.com/", - {{":status", "200"}, {"content-type", "text/plain"}}, - "payload"); - TestDataSource data_source(builder.CreateBundle()); - - mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first; - ASSERT_TRUE(metadata); -} - -TEST_F(WebBundleParserTest, InvalidManifestURL) { - WebBundleBuilder builder(kFallbackUrl, "not-an-absolute-url", - BundleVersion::kB1); - builder.AddExchange("https://test.example.com/", - {{":status", "200"}, {"content-type", "text/plain"}}, - "payload"); - TestDataSource data_source(builder.CreateBundle()); - - ExpectFormatError(ParseBundle(&data_source), - /* should_have_fallback_url */ true); -} - TEST_F(WebBundleParserTest, EmptySignaturesSection) { WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", @@ -818,33 +686,28 @@ } TEST_F(WebBundleParserTest, RelativeURL) { - constexpr BundleVersion kVersions[] = {BundleVersion::kB1, - BundleVersion::kB2}; - for (const auto& version : kVersions) { - WebBundleBuilder builder("path/to/primary_url", "path/to/manifest", - version); - builder.AddExchange("path/to/file.txt", - {{":status", "200"}, {"content-type", "text/plain"}}, - "payload"); - TestDataSource data_source(builder.CreateBundle()); + WebBundleBuilder builder("path/to/primary_url", "path/to/manifest", + BundleVersion::kB2); + builder.AddExchange("path/to/file.txt", + {{":status", "200"}, {"content-type", "text/plain"}}, + "payload"); + TestDataSource data_source(builder.CreateBundle()); - const GURL base_url("https://test.example.com/dir/test.wbn"); - mojom::BundleMetadataPtr metadata = - ParseBundle(&data_source, base_url).first; - EXPECT_EQ(metadata->primary_url, - "https://test.example.com/dir/path/to/primary_url"); - ASSERT_TRUE(metadata); - ASSERT_EQ(metadata->requests.size(), 1u); - auto location = FindResponse( - metadata, GURL("https://test.example.com/dir/path/to/file.txt")); - ASSERT_TRUE(location); - auto response = ParseResponse(&data_source, location, base_url); - ASSERT_TRUE(response); - EXPECT_EQ(response->response_code, 200); - EXPECT_EQ(response->response_headers.size(), 1u); - EXPECT_EQ(response->response_headers["content-type"], "text/plain"); - EXPECT_EQ(data_source.GetPayload(response), "payload"); - } + const GURL base_url("https://test.example.com/dir/test.wbn"); + mojom::BundleMetadataPtr metadata = ParseBundle(&data_source, base_url).first; + EXPECT_EQ(metadata->primary_url, + "https://test.example.com/dir/path/to/primary_url"); + ASSERT_TRUE(metadata); + ASSERT_EQ(metadata->requests.size(), 1u); + auto location = FindResponse( + metadata, GURL("https://test.example.com/dir/path/to/file.txt")); + ASSERT_TRUE(location); + auto response = ParseResponse(&data_source, location, base_url); + ASSERT_TRUE(response); + EXPECT_EQ(response->response_code, 200); + EXPECT_EQ(response->response_headers.size(), 1u); + EXPECT_EQ(response->response_headers["content-type"], "text/plain"); + EXPECT_EQ(data_source.GetPayload(response), "payload"); } TEST_F(WebBundleParserTest, RandomAccessContext) {
diff --git a/components/webapps/browser/android/webapk/webapk_types.h b/components/webapps/browser/android/webapk/webapk_types.h index 221c8855..a012f4e 100644 --- a/components/webapps/browser/android/webapk/webapk_types.h +++ b/components/webapps/browser/android/webapk/webapk_types.h
@@ -46,14 +46,33 @@ // A Java counterpart will be generated for this enum. // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.webapps // +// This enum is used to back UMA/UKM histograms, and should therefore be treated +// as append-only. +// // Indicates the result of an WebAPK install. enum class WebApkInstallResult { SUCCESS = 0, + // Install WebAPK with the installer service (i.e. Google Play) failed. FAILURE = 1, // An install was initiated but it timed out. We did not get a response from // the install service so it is possible that the install will complete some // time in the future. - PROBABLE_FAILURE = 2 + PROBABLE_FAILURE = 2, + + // No install service to complete the install. + NO_INSTALLER = 3, + + SERVER_URL_INVALID = 4, + // Server returns an error or unexpected result. + SERVER_ERROR = 5, + // Request to server timed out. + REQUEST_TIMEOUT = 6, + // The request proto is invalid. + REQUEST_INVALID = 7, + + NOT_ENOUGH_SPACE = 8, + ICON_HASHER_ERROR = 9, + RESULT_MAX = 10, }; } // namespace webapps
diff --git a/components/webcrypto/algorithms/aes_cbc_unittest.cc b/components/webcrypto/algorithms/aes_cbc_unittest.cc index cde7911..f5a9790 100644 --- a/components/webcrypto/algorithms/aes_cbc_unittest.cc +++ b/components/webcrypto/algorithms/aes_cbc_unittest.cc
@@ -89,13 +89,9 @@ // Tests importing of keys (in a variety of formats), errors during import, // encryption, and decryption, using known answers. TEST_F(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_cbc.json", &tests)); - - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; + base::Value::List tests = ReadJsonTestFileAsList("aes_cbc.json"); + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/aes_gcm_unittest.cc b/components/webcrypto/algorithms/aes_gcm_unittest.cc index 89a1dff73..0dfedb8 100644 --- a/components/webcrypto/algorithms/aes_gcm_unittest.cc +++ b/components/webcrypto/algorithms/aes_gcm_unittest.cc
@@ -132,14 +132,11 @@ // * Test decryption with empty input // * Test decryption with tag length of 0. TEST_F(WebCryptoAesGcmTest, SampleSets) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_gcm.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("aes_gcm.json"); // Note that WebCrypto appends the authentication tag to the ciphertext. - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/aes_kw_unittest.cc b/components/webcrypto/algorithms/aes_kw_unittest.cc index a0709e3..857b4bb 100644 --- a/components/webcrypto/algorithms/aes_kw_unittest.cc +++ b/components/webcrypto/algorithms/aes_kw_unittest.cc
@@ -152,10 +152,8 @@ } TEST_F(WebCryptoAesKwTest, UnwrapFailures) { - // This test exercises the code path common to all unwrap operations. - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests)); - const base::Value& test_value = tests.GetListDeprecated()[0]; + auto tests = ReadJsonTestFileAsList("aes_kw.json"); + const base::Value& test_value = tests[0]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -179,13 +177,10 @@ } TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("aes_kw.json"); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -241,10 +236,8 @@ // Unwrap a HMAC key using AES-KW, and then try doing a sign/verify with the // unwrapped key TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests)); - - const base::Value& test_value = tests.GetListDeprecated()[0]; + auto tests = ReadJsonTestFileAsList("aes_kw.json"); + const base::Value& test_value = tests[0]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -294,10 +287,9 @@ } TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapErrors) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests)); // Use 256 bits of data with a 256-bit KEK - const base::Value& test_value = tests.GetListDeprecated()[3]; + auto tests = ReadJsonTestFileAsList("aes_kw.json"); + const base::Value& test_value = tests[3]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -337,10 +329,9 @@ } TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapCorruptData) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests)); // Use 256 bits of data with a 256-bit KEK - const base::Value& test_value = tests.GetListDeprecated()[3]; + auto tests = ReadJsonTestFileAsList("aes_kw.json"); + const base::Value& test_value = tests[3]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/ecdh_unittest.cc b/components/webcrypto/algorithms/ecdh_unittest.cc index 02515ff..d9cd676e 100644 --- a/components/webcrypto/algorithms/ecdh_unittest.cc +++ b/components/webcrypto/algorithms/ecdh_unittest.cc
@@ -75,14 +75,11 @@ class WebCryptoEcdhTest : public WebCryptoTestBase {}; TEST_F(WebCryptoEcdhTest, DeriveBitsKnownAnswer) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("ecdh.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("ecdh.json"); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); + for (const base::Value& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -120,16 +117,12 @@ // 528 bits. ::testing::AssertionResult LoadTestKeys(blink::WebCryptoKey* public_key, blink::WebCryptoKey* private_key) { - base::Value tests; - if (!ReadJsonTestFileAsList("ecdh.json", &tests)) - return ::testing::AssertionFailure() << "Failed loading ecdh.json"; + base::Value::List tests = ReadJsonTestFileAsList("ecdh.json"); const base::DictionaryValue* test = nullptr; bool valid_p521_keys = false; - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; + for (const base::Value& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); EXPECT_TRUE(test_value.is_dict()); test = &base::Value::AsDictionaryValue(test_value); absl::optional<bool> keys = test->FindBoolKey("valid_p521_keys"); @@ -308,10 +301,9 @@ TEST_F(WebCryptoEcdhTest, ImportKeyEmptyUsage) { blink::WebCryptoKey key; - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("ecdh.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("ecdh.json"); + const base::Value& test_value = tests[0]; - const base::Value& test_value = tests.GetListDeprecated()[0]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/ecdsa_unittest.cc b/components/webcrypto/algorithms/ecdsa_unittest.cc index 291bc71..3503a9a 100644 --- a/components/webcrypto/algorithms/ecdsa_unittest.cc +++ b/components/webcrypto/algorithms/ecdsa_unittest.cc
@@ -96,9 +96,9 @@ // Import a public and private keypair from "ec_private_keys.json". It doesn't // really matter which one is used since they are all valid. In this case // using the first one. - base::Value private_keys; - ASSERT_TRUE(ReadJsonTestFileAsList("ec_private_keys.json", &private_keys)); - const base::Value& key_value = private_keys.GetListDeprecated()[0]; + base::Value::List private_keys = + ReadJsonTestFileAsList("ec_private_keys.json"); + const base::Value& key_value = private_keys[0]; ASSERT_TRUE(key_value.is_dict()); const base::DictionaryValue* key_dict = &base::Value::AsDictionaryValue(key_value); @@ -155,14 +155,10 @@ // Tests verify() for ECDSA using an assortment of keys, curves and hashes. // These tests also include expected failures for bad signatures and keys. TEST_F(WebCryptoEcdsaTest, VerifyKnownAnswer) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("ecdsa.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("ecdsa.json"); + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - - const base::Value& test_value = tests.GetListDeprecated()[test_index]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -239,14 +235,11 @@ // Tests importing bad public/private keys in a variety of formats. TEST_F(WebCryptoEcdsaTest, ImportBadKeys) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("bad_ec_keys.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("bad_ec_keys.json"); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -272,14 +265,10 @@ // The test imports a key first using JWK, and then exporting it to JWK and // PKCS8. It does the same thing using PKCS8 as the original source of truth. TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("ec_private_keys.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("ec_private_keys.json"); + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - - const base::Value& test_value = tests.GetListDeprecated()[test_index]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/rsa_oaep_unittest.cc b/components/webcrypto/algorithms/rsa_oaep_unittest.cc index 210c337..fb8f718 100644 --- a/components/webcrypto/algorithms/rsa_oaep_unittest.cc +++ b/components/webcrypto/algorithms/rsa_oaep_unittest.cc
@@ -154,14 +154,10 @@ } TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("rsa_oaep.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("rsa_oaep.json"); + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - - const base::Value& test_value = tests.GetListDeprecated()[test_index]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/rsa_ssa_unittest.cc b/components/webcrypto/algorithms/rsa_ssa_unittest.cc index db13e2b..eb23a328 100644 --- a/components/webcrypto/algorithms/rsa_ssa_unittest.cc +++ b/components/webcrypto/algorithms/rsa_ssa_unittest.cc
@@ -201,18 +201,14 @@ // be imported correctly, however every key after that would actually import // the first key. TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) { - base::Value key_list; - ASSERT_TRUE(ReadJsonTestFileAsList("rsa_private_keys.json", &key_list)); - // For this test to be meaningful the keys MUST be kept alive before importing // new keys. std::vector<blink::WebCryptoKey> live_keys; - for (size_t key_index = 0; key_index < key_list.GetListDeprecated().size(); - ++key_index) { - SCOPED_TRACE(key_index); + base::Value::List keys = ReadJsonTestFileAsList("rsa_private_keys.json"); + for (const auto& key_values : keys) { + SCOPED_TRACE(&key_values - &keys[0]); - const base::Value& key_values = key_list.GetListDeprecated()[key_index]; ASSERT_TRUE(key_values.is_dict()); const base::DictionaryValue* key_values_dict = &base::Value::AsDictionaryValue(key_values); @@ -263,11 +259,10 @@ // that the second import retrieves the first key. See http://crbug.com/378315 // for how that could happen. TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) { - base::Value key_list; - ASSERT_TRUE(ReadJsonTestFileAsList("rsa_private_keys.json", &key_list)); + base::Value::List key_list = ReadJsonTestFileAsList("rsa_private_keys.json"); // Import a 1024-bit private key. - const base::Value& key1_props_value = key_list.GetListDeprecated()[1]; + const base::Value& key1_props_value = key_list[1]; ASSERT_TRUE(key1_props_value.is_dict()); const base::DictionaryValue* key1_props = &base::Value::AsDictionaryValue(key1_props_value); @@ -287,7 +282,7 @@ // Construct a JWK using the modulus of key1, but all the other fields from // another key (also a 1024-bit private key). - base::Value& key2_props_value = key_list.GetListDeprecated()[5]; + base::Value& key2_props_value = key_list[5]; ASSERT_TRUE(key2_props_value.is_dict()); base::DictionaryValue* key2_props = const_cast<base::DictionaryValue*>( &base::Value::AsDictionaryValue(key2_props_value)); @@ -638,9 +633,6 @@ } TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("pkcs1v15_sign.json", &tests)); - // Import the key pair. blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5, @@ -657,12 +649,12 @@ CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5); // Validate the signatures are computed and verified as expected. - std::vector<uint8_t> signature; - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); + base::Value::List tests = ReadJsonTestFileAsList("pkcs1v15_sign.json"); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; + std::vector<uint8_t> signature; + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); + ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value); @@ -996,14 +988,10 @@ // Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected. TEST_F(WebCryptoRsaSsaTest, ImportInvalidKeyData) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("bad_rsa_keys.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("bad_rsa_keys.json"); + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - - const base::Value& test_value = tests.GetListDeprecated()[test_index]; ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/sha_unittest.cc b/components/webcrypto/algorithms/sha_unittest.cc index cec19aa..5345d17 100644 --- a/components/webcrypto/algorithms/sha_unittest.cc +++ b/components/webcrypto/algorithms/sha_unittest.cc
@@ -22,13 +22,10 @@ class WebCryptoShaTest : public WebCryptoTestBase {}; TEST_F(WebCryptoShaTest, DigestSampleSets) { - base::Value tests; - ASSERT_TRUE(ReadJsonTestFileAsList("sha.json", &tests)); + base::Value::List tests = ReadJsonTestFileAsList("sha.json"); - for (size_t test_index = 0; test_index < tests.GetListDeprecated().size(); - ++test_index) { - SCOPED_TRACE(test_index); - const base::Value& test_value = tests.GetListDeprecated()[test_index]; + for (const auto& test_value : tests) { + SCOPED_TRACE(&test_value - &tests[0]); ASSERT_TRUE(test_value.is_dict()); const base::DictionaryValue* test = &base::Value::AsDictionaryValue(test_value);
diff --git a/components/webcrypto/algorithms/test_helpers.cc b/components/webcrypto/algorithms/test_helpers.cc index 1e8de72..f72b404 100644 --- a/components/webcrypto/algorithms/test_helpers.cc +++ b/components/webcrypto/algorithms/test_helpers.cc
@@ -162,17 +162,12 @@ return std::vector<uint8_t>(json.begin(), json.end()); } -::testing::AssertionResult ReadJsonTestFileAsList(const char* test_file_name, - base::Value* value) { +base::Value::List ReadJsonTestFileAsList(const char* test_file_name) { absl::optional<base::Value> result = ReadJsonTestFile(test_file_name); - if (!result) - return ::testing::AssertionFailure() << "Couldn't load JSON"; + CHECK(result.has_value()); + CHECK(result->is_list()); - if (!result->is_list()) - return ::testing::AssertionFailure() << "The JSON was not a list"; - - *value = std::move(*result); - return ::testing::AssertionSuccess(); + return std::move(result->GetList()); } std::vector<uint8_t> GetBytesFromHexString(const base::Value* dict,
diff --git a/components/webcrypto/algorithms/test_helpers.h b/components/webcrypto/algorithms/test_helpers.h index 63e5cbd..59fd3f39 100644 --- a/components/webcrypto/algorithms/test_helpers.h +++ b/components/webcrypto/algorithms/test_helpers.h
@@ -88,8 +88,7 @@ // Reads "//components/test/data/webcrypto/" + test_file_name as a JSON // file, asserts that the contained JSON is a list, and returns that list. -::testing::AssertionResult ReadJsonTestFileAsList(const char* test_file_name, - base::Value* list); +base::Value::List ReadJsonTestFileAsList(const char* test_file_name); // Reads a string property from the dictionary |dict| with path |property_name| // (which can include periods for nested dictionaries). Interprets the
diff --git a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h index e3267b5..99f642c 100644 --- a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h +++ b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h
@@ -13,8 +13,11 @@ @interface WebContentsOcclusionCheckerMac : NSObject + (instancetype)sharedInstance; -// Updates the visibility of the webContentsViewCocoa in `window`. -- (void)updateWebContentsVisibilityInWindow:(NSWindow*)window; +// Returns YES if webcontents visibility updates will occur on the next pass +// of the run loop. +- (BOOL)willUpdateWebContentsVisibility; +// Updates the visibility of each WebContentsViewCocoa instance. +- (void)notifyUpdateWebContentsVisibility; // Computes and updates the visibility of the `webContentsViewCocoa`. - (void)updateWebContentsVisibility:(WebContentsViewCocoa*)webContentsViewCocoa;
diff --git a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm index cde0028c..39f24aa 100644 --- a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm +++ b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm
@@ -33,6 +33,8 @@ NSWindow* _windowResizingMovingOrClosing; NSWindow* _windowReceivingFullscreenTransitionNotifications; BOOL _displaysAreAsleep; + BOOL _willUpdateWebContentsVisibility; + BOOL _updatingWebContentsVisibility; } // Computes and returns the `window`'s visibility state, a hybrid of // macOS's and our manual occlusion calculation. @@ -82,8 +84,10 @@ self, _cmd, orderingMode, otherWindowNumber); // The window order has changed so update web contents visibility. - [[WebContentsOcclusionCheckerMac sharedInstance] - notifyUpdateWebContentsVisibility]; + if (kEnhancedWindowOcclusionDetection.Get()) { + [[WebContentsOcclusionCheckerMac sharedInstance] + notifyUpdateWebContentsVisibility]; + } } - (void)setUpNotifications { @@ -175,7 +179,7 @@ } - (void)windowChangedOcclusionState:(NSNotification*)notification { - [self updateWebContentsVisibilityInWindow:[notification object]]; + [self notifyUpdateWebContentsVisibility]; } - (void)displaysDidSleep:(NSNotification*)notification { @@ -196,7 +200,15 @@ _windowReceivingFullscreenTransitionNotifications = nil; } +- (BOOL)willUpdateWebContentsVisibility { + return _willUpdateWebContentsVisibility; +} + - (void)notifyUpdateWebContentsVisibility { + if (_willUpdateWebContentsVisibility) { + return; + } + // https://crbug.com/1300929 covers a crash where a webcontents gets added to // a window, triggering an update to its visibility state. A visibility state // observer creates a bubble, and that bubble triggers a call to @@ -209,19 +221,32 @@ // entering its observer code twice (as happened in the bug). By making the // occlusion status update occur away from the notification we can avoid the // reentrancy problems with visibility observers. - [NSObject cancelPreviousPerformRequestsWithTarget:self - selector:@selector - (_notifyUpdateWebContentsVisibility) - object:nil]; + _willUpdateWebContentsVisibility = YES; [self performSelector:@selector(_notifyUpdateWebContentsVisibility) withObject:nil afterDelay:0]; } - (void)_notifyUpdateWebContentsVisibility { - for (NSWindow* window in [[NSApplication sharedApplication] orderedWindows]) { + _willUpdateWebContentsVisibility = NO; + + DCHECK(!_updatingWebContentsVisibility); + + _updatingWebContentsVisibility = YES; + + // Copy the list to avoid mutation exceptions (imagine the visibility + // update triggers a visibility watcher that brings a new window + // onscreen). Emperically, -orderedWindows returns a new list each time, + // so it's likely already a copy. The API, however, does not make any + // guarantees about what it returns, and methods like + // -[NSWindow childWindows] apparently return the actual internal array. + base::scoped_nsobject<NSArray<NSWindow*>> orderedWindows( + [[[NSApplication sharedApplication] orderedWindows] copy]); + for (NSWindow* window in orderedWindows.get()) { [self updateWebContentsVisibilityInWindow:window]; } + + _updatingWebContentsVisibility = NO; } - (void)updateWebContentsVisibilityInWindow:(NSWindow*)window { @@ -271,11 +296,12 @@ NSRect windowFrame = [window frame]; - NSArray<NSWindow*>* windowsFromFrontToBack = - [[NSApplication sharedApplication] orderedWindows]; + // See the note about avoiding mutation exceptions above. + base::scoped_nsobject<NSArray<NSWindow*>> windowsFromFrontToBack( + [[[NSApplication sharedApplication] orderedWindows] copy]); // Determine if there's a window occluding our window. - for (NSWindow* nextWindow in windowsFromFrontToBack) { + for (NSWindow* nextWindow in windowsFromFrontToBack.get()) { if (![nextWindow isVisible]) { continue; }
diff --git a/content/app_shim_remote_cocoa/window_occlusion_browsertest_mac.mm b/content/app_shim_remote_cocoa/window_occlusion_browsertest_mac.mm index 1eae55d..690427d 100644 --- a/content/app_shim_remote_cocoa/window_occlusion_browsertest_mac.mm +++ b/content/app_shim_remote_cocoa/window_occlusion_browsertest_mac.mm
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "base/mac/foundation_util.h" #include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_objc_class_swizzler.h" #include "base/test/scoped_feature_list.h" @@ -34,11 +35,13 @@ BOOL _miniaturizedForTesting; } @property(assign, nonatomic) BOOL occludedForTesting; +@property(assign, nonatomic) BOOL modifyingChildWindowList; @end @implementation WebContentsHostWindowForOcclusionTesting @synthesize occludedForTesting = _occludedForTesting; +@synthesize modifyingChildWindowList = _modifyingChildWindowList; - (NSWindowOcclusionState)occlusionState { return _occludedForTesting ? 0 : NSWindowOcclusionStateVisible; @@ -60,6 +63,37 @@ return _miniaturizedForTesting; } +- (void)addChildWindow:(NSWindow*)childWindow + ordered:(NSWindowOrderingMode)place { + _modifyingChildWindowList = YES; + [super addChildWindow:childWindow ordered:place]; + _modifyingChildWindowList = NO; +} + +- (void)removeChildWindow:(NSWindow*)childWindow { + _modifyingChildWindowList = YES; + [super removeChildWindow:childWindow]; + _modifyingChildWindowList = NO; +} + +@end + +@interface WebContentsViewCocoaForOcclusionTesting : WebContentsViewCocoa +@end + +@implementation WebContentsViewCocoaForOcclusionTesting + +- (void)updateWebContentsVisibility: + (remote_cocoa::mojom::Visibility)visibility { + WebContentsHostWindowForOcclusionTesting* hostWindow = + base::mac::ObjCCast<WebContentsHostWindowForOcclusionTesting>( + [self window]); + + EXPECT_FALSE([hostWindow modifyingChildWindowList]); + + [super updateWebContentsVisibility:visibility]; +} + @end // A class that waits for invocations of the private @@ -261,31 +295,49 @@ class WindowOcclusionBrowserTestMac : public ContentBrowserTest { public: void WaitForOcclusionUpdate() { + if (![[NSClassFromString(@"WebContentsOcclusionCheckerMac") sharedInstance] + willUpdateWebContentsVisibility]) { + return; + } + base::scoped_nsobject<WebContentVisibilityUpdateWatcher> watcher( [[WebContentVisibilityUpdateWatcher alloc] init]); [watcher waitForOcclusionUpdate]; } + static WebContentsViewCocoaForOcclusionTesting* WebContentsInWindow( + NSRect contentRect, + NSWindowStyleMask styleMask = NSWindowStyleMaskClosable) { + WebContentsHostWindowForOcclusionTesting* window = + [[[WebContentsHostWindowForOcclusionTesting alloc] + initWithContentRect:contentRect + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:YES] autorelease]; + NSRect window_frame = [NSWindow frameRectForContentRect:contentRect + styleMask:styleMask]; + window_frame.origin = NSMakePoint(20.0, 200.0); + [window setFrame:window_frame display:NO]; + [window setReleasedWhenClosed:NO]; + + const NSRect kWebContentsFrame = NSMakeRect(0.0, 0.0, 10.0, 10.0); + WebContentsViewCocoaForOcclusionTesting* web_contents_view = + [[[WebContentsViewCocoaForOcclusionTesting alloc] + initWithFrame:kWebContentsFrame] autorelease]; + [[window contentView] addSubview:web_contents_view]; + + return web_contents_view; + } + // Creates |window_a| with a visible (i.e. unoccluded) WebContentsViewCocoa. void InitWindowA() { const NSRect kWindowAContentRect = NSMakeRect(0.0, 0.0, 80.0, 60.0); - const NSWindowStyleMask kWindowStyleMask = NSWindowStyleMaskClosable; - window_a.reset([[WebContentsHostWindowForOcclusionTesting alloc] - initWithContentRect:kWindowAContentRect - styleMask:kWindowStyleMask - backing:NSBackingStoreBuffered - defer:YES]); - NSRect window_frame = [NSWindow frameRectForContentRect:kWindowAContentRect - styleMask:kWindowStyleMask]; - window_frame.origin = NSMakePoint(20.0, 200.0); - [window_a setFrame:window_frame display:NO]; - [window_a setTitle:@"window_a"]; - [window_a setReleasedWhenClosed:NO]; - - const NSRect kWebContentsFrame = NSMakeRect(0.0, 0.0, 10.0, 10.0); window_a_web_contents_view_cocoa.reset( - [[WebContentsViewCocoa alloc] initWithFrame:kWebContentsFrame]); - [[window_a contentView] addSubview:window_a_web_contents_view_cocoa]; + [WebContentsInWindow(kWindowAContentRect) retain]); + window_a.reset( + base::mac::ObjCCast<WebContentsHostWindowForOcclusionTesting>( + [[window_a_web_contents_view_cocoa window] retain])); + [window_a setTitle:@"window_a"]; // Set up a fake host so we can check the occlusion status. [window_a_web_contents_view_cocoa setHost:&_host_a]; @@ -299,19 +351,16 @@ void InitWindowB(NSRect window_frame = NSZeroRect) { const NSRect kWindowBContentRect = NSMakeRect(0.0, 0.0, 40.0, 40.0); - const NSWindowStyleMask kWindowStyleMask = NSWindowStyleMaskClosable; - window_b.reset([[WebContentsHostWindowForOcclusionTesting alloc] - initWithContentRect:kWindowBContentRect - styleMask:kWindowStyleMask - backing:NSBackingStoreBuffered - defer:YES]); + window_b.reset( + base::mac::ObjCCast<WebContentsHostWindowForOcclusionTesting>( + [[WebContentsInWindow(kWindowBContentRect) window] retain])); [window_b setTitle:@"window_b"]; - [window_b setReleasedWhenClosed:NO]; if (NSIsEmptyRect(window_frame)) { - window_frame.size = [NSWindow frameRectForContentRect:kWindowBContentRect - styleMask:kWindowStyleMask] - .size; + window_frame.size = + [NSWindow frameRectForContentRect:kWindowBContentRect + styleMask:[window_b styleMask]] + .size; } [window_b setFrame:window_frame display:NO]; @@ -357,13 +406,31 @@ } void MiniaturizeWindow(NSWindow* window) { - [window_a miniaturize:nil]; + [window miniaturize:nil]; WaitForOcclusionUpdate(); } void DeminiaturizeWindow(NSWindow* window) { - [window_a deminiaturize:nil]; + [window deminiaturize:nil]; + + WaitForOcclusionUpdate(); + } + + void AddSubviewOfView(NSView* subview, NSView* view) { + [view addSubview:subview]; + + WaitForOcclusionUpdate(); + } + + void SetViewHidden(NSView* view, BOOL hidden) { + [view setHidden:hidden]; + + WaitForOcclusionUpdate(); + } + + void RemoveViewFromSuperview(NSView* view) { + [view removeFromSuperview]; WaitForOcclusionUpdate(); } @@ -505,12 +572,16 @@ [window_a setOccludedForTesting:YES]; PostNotification(NSWindowDidChangeOcclusionStateNotification, window_a); + WaitForOcclusionUpdate(); + EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kOccluded); [window_a setOccludedForTesting:NO]; PostNotification(NSWindowDidChangeOcclusionStateNotification, window_a); + WaitForOcclusionUpdate(); + EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); } @@ -637,13 +708,8 @@ // Create a window_c on top of them both. const NSRect kWindowCContentRect = NSMakeRect(0.0, 0.0, 80.0, 60.0); base::scoped_nsobject<NSWindow> window_c( - [[WebContentsHostWindowForOcclusionTesting alloc] - initWithContentRect:kWindowCContentRect - styleMask:NSWindowStyleMaskClosable - backing:NSBackingStoreBuffered - defer:YES]); - [window_c setTitle:@"window_a"]; - [window_c setReleasedWhenClosed:NO]; + [[WebContentsInWindow(kWindowCContentRect) window] retain]); + [window_c setTitle:@"window_c"]; // Configure it for the test. [window_c setFrame:[window_a frame] display:NO]; @@ -704,6 +770,8 @@ PostNotification(NSWindowDidChangeOcclusionStateNotification, window_a); + WaitForOcclusionUpdate(); + EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); @@ -726,6 +794,8 @@ PostNotification(NSWindowDidChangeOcclusionStateNotification, window_a); + WaitForOcclusionUpdate(); + EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); } @@ -743,7 +813,8 @@ // Create a second web contents. const NSRect kWebContentsBFrame = NSMakeRect(0.0, 0.0, 10.0, 10.0); WebContentsViewCocoa* web_contents_b = - [[WebContentsViewCocoa alloc] initWithFrame:kWebContentsBFrame]; + [[WebContentsViewCocoaForOcclusionTesting alloc] + initWithFrame:kWebContentsBFrame]; [[window_a contentView] addSubview:web_contents_b]; WebContentsNSViewHostStub host_2; [web_contents_b setHost:&host_2]; @@ -751,7 +822,8 @@ const NSRect kWebContentsCFrame = NSMakeRect(0.0, 20.0, 10.0, 10.0); WebContentsViewCocoa* web_contents_c = - [[WebContentsViewCocoa alloc] initWithFrame:kWebContentsCFrame]; + [[WebContentsViewCocoaForOcclusionTesting alloc] + initWithFrame:kWebContentsCFrame]; [[window_a contentView] addSubview:web_contents_c]; WebContentsNSViewHostStub host_3; [web_contents_c setHost:&host_3]; @@ -790,20 +862,20 @@ EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); - [window_a_web_contents_view_cocoa setHidden:YES]; + SetViewHidden(window_a_web_contents_view_cocoa, YES); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kHidden); - [window_a_web_contents_view_cocoa setHidden:NO]; + SetViewHidden(window_a_web_contents_view_cocoa, NO); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); // Hiding the superview should have the same effect. - [[window_a_web_contents_view_cocoa superview] setHidden:YES]; + SetViewHidden([window_a_web_contents_view_cocoa superview], YES); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kHidden); - [[window_a_web_contents_view_cocoa superview] setHidden:NO]; + SetViewHidden([window_a_web_contents_view_cocoa superview], NO); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); } @@ -818,12 +890,12 @@ EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); - [window_a_web_contents_view_cocoa removeFromSuperview]; + RemoveViewFromSuperview(window_a_web_contents_view_cocoa); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kHidden); // Adding it back should make it visible. - [[window_a contentView] addSubview:window_a_web_contents_view_cocoa]; + AddSubviewOfView(window_a_web_contents_view_cocoa, [window_a contentView]); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); @@ -832,16 +904,17 @@ base::scoped_nsobject<NSView> tmpView( [[NSView alloc] initWithFrame:kTmpViewFrame]); [[window_a contentView] addSubview:tmpView]; - [window_a_web_contents_view_cocoa removeFromSuperview]; - [tmpView addSubview:window_a_web_contents_view_cocoa]; + AddSubviewOfView(tmpView, [window_a contentView]); + RemoveViewFromSuperview(window_a_web_contents_view_cocoa); + AddSubviewOfView(window_a_web_contents_view_cocoa, tmpView); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); - [tmpView removeFromSuperview]; + RemoveViewFromSuperview(tmpView); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kHidden); - [[window_a contentView] addSubview:tmpView]; + AddSubviewOfView(tmpView, [window_a contentView]); EXPECT_EQ(WindowAWebContentsVisibility(), remote_cocoa::mojom::Visibility::kVisible); } @@ -868,4 +941,42 @@ remote_cocoa::mojom::Visibility::kVisible); } +// Tests that occlusion updates only occur after a child window has been +// added to or removed from a parent. In Chrome, some webcontents visibility +// watchers add child windows (bubbles) when visibility changes. We want to +// avoid the situation where a browser component adds a child window, +// triggering a visility update, which causes a visibility watcher to add +// a second child window (while we're still inside AppKit code adding the +// first). +IN_PROC_BROWSER_TEST_F( + WindowOcclusionBrowserTestMacWithOcclusionDetectionFeature, + ChildWindowListMutationDuringManualOcclusionDetection) { + InitWindowA(); + + const NSRect kContentRect = NSMakeRect(0.0, 0.0, 20.0, 20.0); + WebContentsViewCocoaForOcclusionTesting* child_window_web_contents = + WindowOcclusionBrowserTestMac::WebContentsInWindow( + kContentRect, NSWindowStyleMaskBorderless); + + // Clear out any pending occlusion updates from the window creation. + WaitForOcclusionUpdate(); + + // Add the window with the webcontents as a child. The child window coming + // onscreen will trigger a visibility update. A check inside the webcontents + // will ensure the update isn't synchronous with the window as it modifies + // its child window list. + [window_a addChildWindow:[child_window_web_contents window] + ordered:NSWindowAbove]; + + // The visbility update should still be pending (deferred until the next + // pass of the run loop). + EXPECT_TRUE([[NSClassFromString(@"WebContentsOcclusionCheckerMac") + sharedInstance] willUpdateWebContentsVisibility]); + + WaitForOcclusionUpdate(); + + // Modify the child window list by removing a child window. + [window_a removeChildWindow:[child_window_web_contents window]]; +} + } // namespace content
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 0732f77..a6ee40c 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -643,6 +643,7 @@ "cache_storage/cache_storage.h", "cache_storage/cache_storage_blob_to_disk_cache.cc", "cache_storage/cache_storage_blob_to_disk_cache.h", + "cache_storage/cache_storage_cache.cc", "cache_storage/cache_storage_cache.h", "cache_storage/cache_storage_cache_entry_handler.cc", "cache_storage/cache_storage_cache_entry_handler.h", @@ -671,12 +672,6 @@ "cache_storage/cache_storage_scheduler_types.h", "cache_storage/cache_storage_trace_utils.cc", "cache_storage/cache_storage_trace_utils.h", - "cache_storage/legacy/legacy_cache_storage.cc", - "cache_storage/legacy/legacy_cache_storage.h", - "cache_storage/legacy/legacy_cache_storage_cache.cc", - "cache_storage/legacy/legacy_cache_storage_cache.h", - "cache_storage/legacy/legacy_cache_storage_manager.cc", - "cache_storage/legacy/legacy_cache_storage_manager.h", "cache_storage/scoped_writable_entry.h", "can_commit_status.h", "child_process_launcher.cc", @@ -2462,9 +2457,13 @@ "font_access/font_enumeration_data_source_fuchsia.cc", "font_access/font_enumeration_data_source_fuchsia.h", "memory/swap_metrics_driver_impl_fuchsia.cc", + "renderer_host/media/media_resource_provider_fuchsia.cc", + "renderer_host/media/media_resource_provider_fuchsia.h", "speech/tts_fuchsia.cc", ] deps += [ + "//media/fuchsia/cdm/service", + "//media/fuchsia/mojom:fuchsia_media_resource_provider", "//third_party/abseil-cpp:absl", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.accessibility.semantics", "//third_party/fuchsia-sdk/sdk/pkg/inspect",
diff --git a/content/browser/attribution_reporting/attribution_src_browsertest.cc b/content/browser/attribution_reporting/attribution_src_browsertest.cc index b114b60..16e62db 100644 --- a/content/browser/attribution_reporting/attribution_src_browsertest.cc +++ b/content/browser/attribution_reporting/attribution_src_browsertest.cc
@@ -516,7 +516,7 @@ EXPECT_THAT(trigger_data.front()->filters->filter_values, IsEmpty()); EXPECT_FALSE(trigger_data.front()->debug_key); EXPECT_EQ(trigger_data.front()->event_triggers.size(), 1u); - EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 10u); + EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 7u); EXPECT_THAT( trigger_data.front()->event_triggers.front()->filters->filter_values, IsEmpty()); @@ -696,7 +696,7 @@ EXPECT_EQ(trigger_data.front()->reporting_origin, url::Origin::Create(register_url)); EXPECT_EQ(trigger_data.front()->event_triggers.size(), 1u); - EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 10u); + EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 7u); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -788,7 +788,7 @@ // Both triggers should be processed. EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 5u); - EXPECT_EQ(trigger_data.back()->event_triggers.front()->data, 10u); + EXPECT_EQ(trigger_data.back()->event_triggers.front()->data, 7u); // Middle redirect source should be ignored. EXPECT_EQ(data_host->source_data().size(), 0u); @@ -1087,7 +1087,7 @@ // Only the second trigger is registered. EXPECT_EQ(trigger_data.size(), 1u); EXPECT_EQ(trigger_data.front()->event_triggers.size(), 1u); - EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 10u); + EXPECT_EQ(trigger_data.front()->event_triggers.front()->data, 7u); } INSTANTIATE_TEST_SUITE_P( @@ -1252,7 +1252,7 @@ EXPECT_EQ(trigger_data.size(), expected_triggers); EXPECT_EQ(trigger_data.back()->event_triggers.size(), 1u); - EXPECT_EQ(trigger_data.back()->event_triggers.front()->data, 10u); + EXPECT_EQ(trigger_data.back()->event_triggers.front()->data, 7u); } INSTANTIATE_TEST_SUITE_P(
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc index 1b56147..fc3c8a82 100644 --- a/content/browser/attribution_reporting/attributions_browsertest.cc +++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -257,10 +257,11 @@ EXPECT_TRUE(ExecJs(shell(), "simulateClick('link');")); observer.Wait(); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE(ExecJs(web_contents(), - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -290,10 +291,11 @@ conversion_url, url::Origin::Create(conversion_url)))); observer.Wait(); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE(ExecJs(web_contents(), - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); base::RunLoop run_loop; base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( @@ -329,10 +331,10 @@ conversion_url, register_url))); observer.Wait(); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE(ExecJs(web_contents(), - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -377,10 +379,10 @@ WebContents* popup_contents = new_shell_observer.GetShell()->web_contents(); observer.Wait(); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE(ExecJs(popup_contents, - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(page_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(popup_contents, JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -418,9 +420,12 @@ EXPECT_TRUE(ExecJs(shell(), "simulateClick('link');")); observer.Wait(); - EXPECT_TRUE(ExecJs(Shell::windows()[1]->web_contents(), - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE( + ExecJs(Shell::windows()[1]->web_contents(), + JsReplace("createAttributionSrcImg($1);", register_trigger_url))); + expected_report.WaitForReport(); } @@ -459,10 +464,10 @@ EXPECT_TRUE(ExecJs(shell(), "simulateClick('link');")); observer.Wait(); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE(ExecJs(web_contents(), - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -510,10 +515,10 @@ "/attribution_reporting/page_with_conversion_redirect.html"); EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE(ExecJs(web_contents(), - JsReplace("registerConversion({data: 7, origin: $1})", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -568,10 +573,10 @@ EXPECT_TRUE(ExecJs(shell2, "simulateClick('link');")); second_nav_observer.Wait(); - // Register a conversion after both impressions have been registered. - EXPECT_TRUE( - ExecJs(shell2, JsReplace("registerConversion({data: 7, origin: $1})", - reporting_origin))); + GURL register_trigger_url = https_server()->GetURL( + "d.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs( + shell2, JsReplace("createAttributionSrcImg($1);", register_trigger_url))); expected_report.WaitForReport(); } @@ -628,15 +633,16 @@ EXPECT_TRUE(ExecJs(shell2, "simulateClick('link');")); second_nav_observer.Wait(); - // Register a conversion after both impressions have been registered. - EXPECT_TRUE( - ExecJs(shell2, JsReplace("registerConversion({data: 7, origin: $1})", - reporting_origin))); + GURL register_trigger_url = https_server()->GetURL( + "d.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs( + shell2, JsReplace("createAttributionSrcImg($1);", register_trigger_url))); + expected_report.WaitForReport(); } IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, - EventSourceImpressionWithDebugKeyConversion_ReportSent) { + EventSourceWithDebugKeyConversion_ReportSent) { // Expected reports must be registered before the server starts. ExpectedReportWaiter expected_report( GURL("https://a.test/.well-known/attribution-reporting/" @@ -664,11 +670,10 @@ "b.test", "/attribution_reporting/page_with_conversion_redirect.html"); EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); - EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 1});)", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -698,11 +703,10 @@ "b.test", "/attribution_reporting/page_with_conversion_redirect.html"); EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); - EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 1});)", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -710,7 +714,7 @@ IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, EventSourceImpressionConversionFromJS_ReportSent) { // Expected reports must be registered before the server starts. - // 123 in the `registerConversion` call below is sanitized to 1 in + // 7 in the `registerConversion` call below is sanitized to 1 in // the report's `trigger_data`. ExpectedReportWaiter expected_report( GURL("https://a.test/.well-known/attribution-reporting/" @@ -733,11 +737,10 @@ "d.test", "/attribution_reporting/page_with_conversion_redirect.html"); EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); - EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 123});)", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report.WaitForReport(); } @@ -829,50 +832,6 @@ expected_report.WaitForReport(); } -IN_PROC_BROWSER_TEST_F( - AttributionsBrowserTest, - AttributionSrcSourceAndNonAttributionSrcTrigger_ReportSent) { - // Expected reports must be registered before the server starts. - ExpectedReportWaiter expected_report( - GURL("https://a.test/.well-known/attribution-reporting/" - "report-event-attribution"), - /*attribution_destination=*/"https://d.test", - /*source_event_id=*/"5", /*source_type=*/"event", /*trigger_data=*/"1", - https_server()); - expected_report.trigger_debug_key = "789"; - ASSERT_TRUE(https_server()->Start()); - - EXPECT_TRUE(NavigateToURL( - web_contents(), - https_server()->GetURL( - "a.test", "/set-cookie?ar_debug=1;HttpOnly;Secure;SameSite=None"))); - - EXPECT_TRUE(NavigateToURL( - web_contents(), - https_server()->GetURL( - "b.test", - "/attribution_reporting/page_with_impression_creator.html"))); - - RegisterSource(https_server()->GetURL( - "a.test", "/attribution_reporting/register_source_headers.html")); - - EXPECT_TRUE(NavigateToURL( - web_contents(), - https_server()->GetURL( - "d.test", - "/attribution_reporting/page_with_conversion_redirect.html"))); - - EXPECT_TRUE(ExecJs( - web_contents(), - JsReplace( - "createTrackingPixel($1);", - https_server()->GetURL("a.test", - "/attribution_reporting/" - "register_trigger_headers_all_params.html")))); - - expected_report.WaitForReport(); -} - IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, ImpressionConversionWithDedupKey_Deduped) { // Expected reports must be registered before the server starts. @@ -881,14 +840,14 @@ "report-event-attribution"), /*attribution_destination=*/"https://b.test", /*source_event_id=*/"1", /*source_type=*/"navigation", - /*trigger_data=*/"7", https_server()); + /*trigger_data=*/"1", https_server()); // 12 below is sanitized to 4 here by `SanitizeTriggerData()`. ExpectedReportWaiter expected_report2( GURL("https://a.test/.well-known/attribution-reporting/" "report-event-attribution"), /*attribution_destination=*/"https://b.test", /*source_event_id=*/"1", /*source_type=*/"navigation", - /*trigger_data=*/"4", https_server()); + /*trigger_data=*/"7", https_server()); ASSERT_TRUE(https_server()->Start()); GURL impression_url = https_server()->GetURL( @@ -912,27 +871,24 @@ EXPECT_TRUE(ExecJs(shell(), "simulateClick('link');")); observer.Wait(); + GURL register_trigger_with_dedup_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers_dedup.html"); EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 7, - origin: $1, - dedupKey: 123});)", - url::Origin::Create(impression_url)))); + ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_with_dedup_url))); expected_report1.WaitForReport(); // This report should be deduped against the previous one. EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 9, - origin: $1, - dedupKey: 123});)", - url::Origin::Create(impression_url)))); + ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_with_dedup_url))); // This report should be received, as it has a different dedupKey. - EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 12, - origin: $1, - dedupKey: 456});)", - url::Origin::Create(impression_url)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); expected_report2.WaitForReport(); } @@ -994,11 +950,10 @@ // Register a conversion with the original page as the reporting origin during // pre-rendering. - EXPECT_TRUE( - ExecJs(prerender_rfh, JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 123});)", - url::Origin::Create(kImpressionUrl)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(prerender_rfh, JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); // Verify that registering a conversion had no effect on reports, as the // impressions were never passed to the conversion URL, as the page was only @@ -1053,12 +1008,10 @@ content::RenderFrameHost* prerender_rfh = prerender_helper_.GetPrerenderedMainFrameHost(host_id); - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE( - ExecJs(prerender_rfh, JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 123});)", - url::Origin::Create(kImpressionUrl)))); + GURL register_trigger_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_headers.html"); + EXPECT_TRUE(ExecJs(prerender_rfh, JsReplace("createAttributionSrcImg($1);", + register_trigger_url))); // Navigate to pre-rendered page, bringing it to the fore. prerender_helper_.NavigatePrimaryPage(kConversionUrl);
diff --git a/content/browser/attribution_reporting/trigger_registration_browsertest.cc b/content/browser/attribution_reporting/trigger_registration_browsertest.cc index 78489cb4..2151a64 100644 --- a/content/browser/attribution_reporting/trigger_registration_browsertest.cc +++ b/content/browser/attribution_reporting/trigger_registration_browsertest.cc
@@ -573,7 +573,7 @@ url::Origin::Create(register_url)); EXPECT_THAT( trigger_data2.front()->event_triggers, - ElementsAre(Pointee(Field(&blink::mojom::EventTriggerData::data, 10)))); + ElementsAre(Pointee(Field(&blink::mojom::EventTriggerData::data, 7)))); } } // namespace content
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc index ddca8c81..c5a6f0a 100644 --- a/content/browser/browser_interface_binders.cc +++ b/content/browser/browser_interface_binders.cc
@@ -193,7 +193,12 @@ #if BUILDFLAG(IS_CHROMEOS) #include "content/browser/lock_screen/lock_screen_service_impl.h" #include "third_party/blink/public/mojom/lock_screen/lock_screen.mojom.h" -#endif // BUILDFLAG(IS_CHROMEOS) +#endif + +#if BUILDFLAG(IS_FUCHSIA) +#include "content/browser/renderer_host/media/media_resource_provider_fuchsia.h" +#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h" +#endif namespace blink { class StorageKey; @@ -1170,6 +1175,11 @@ base::BindRepeating(&LockScreenServiceImpl::Create)); } #endif + +#if BUILDFLAG(IS_FUCHSIA) + map->Add<media::mojom::FuchsiaMediaResourceProvider>( + base::BindRepeating(&MediaResourceProviderFuchsia::Bind)); +#endif } void PopulateBinderMap(RenderFrameHostImpl* host, mojo::BinderMap* map) {
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc index 0abc7d6..5923cfd 100644 --- a/content/browser/cache_storage/cache_storage.cc +++ b/content/browser/cache_storage/cache_storage.cc
@@ -3,12 +3,1446 @@ // found in the LICENSE file. #include "content/browser/cache_storage/cache_storage.h" + +#include <stddef.h> + +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "base/barrier_closure.h" +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/containers/contains.h" +#include "base/files/file_util.h" +#include "base/files/memory_mapped_file.h" +#include "base/guid.h" +#include "base/hash/sha1.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" +#include "base/metrics/histogram_macros.h" +#include "base/numerics/safe_conversions.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/task/sequenced_task_runner.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/traced_value.h" +#include "build/build_config.h" +#include "content/browser/cache_storage/cache_storage.pb.h" +#include "content/browser/cache_storage/cache_storage_cache.h" +#include "content/browser/cache_storage/cache_storage_cache_handle.h" +#include "content/browser/cache_storage/cache_storage_histogram_utils.h" +#include "content/browser/cache_storage/cache_storage_index.h" +#include "content/browser/cache_storage/cache_storage_manager.h" +#include "content/browser/cache_storage/cache_storage_quota_client.h" +#include "content/browser/cache_storage/cache_storage_scheduler.h" +#include "content/browser/cache_storage/cache_storage_trace_utils.h" +#include "content/common/background_fetch/background_fetch_types.h" +#include "crypto/symmetric_key.h" +#include "net/base/directory_lister.h" +#include "net/base/net_errors.h" +#include "storage/browser/blob/blob_storage_context.h" +#include "storage/browser/quota/quota_manager_proxy.h" #include "third_party/blink/public/common/storage_key/storage_key.h" +#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" + +using blink::mojom::CacheStorageError; +using blink::mojom::StorageType; +using crypto::SymmetricKey; namespace content { -constexpr int64_t CacheStorage::kSizeUnknown; -CacheStorage::CacheStorage(const blink::StorageKey& storage_key) - : storage_key_(storage_key) {} +namespace { + +std::string HexedHash(const std::string& value) { + std::string value_hash = base::SHA1HashString(value); + std::string valued_hexed_hash = base::ToLowerASCII( + base::HexEncode(value_hash.c_str(), value_hash.length())); + return valued_hexed_hash; +} + +void SizeRetrievedFromAllCaches(std::unique_ptr<int64_t> accumulator, + CacheStorage::SizeCallback callback) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), *accumulator)); +} + +} // namespace + +const char CacheStorage::kIndexFileName[] = "index.txt"; + +struct CacheStorage::CacheMatchResponse { + CacheMatchResponse() = default; + ~CacheMatchResponse() = default; + + CacheStorageError error; + blink::mojom::FetchAPIResponsePtr response; +}; + +// Handles the loading and clean up of CacheStorageCache objects. +class CacheStorage::CacheLoader { + public: + using CacheAndErrorCallback = + base::OnceCallback<void(std::unique_ptr<CacheStorageCache>, + CacheStorageError status)>; + using BoolCallback = base::OnceCallback<void(bool)>; + using CacheStorageIndexLoadCallback = + base::OnceCallback<void(std::unique_ptr<CacheStorageIndex>)>; + + CacheLoader(base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + CacheStorage* cache_storage, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) + : cache_task_runner_(cache_task_runner), + scheduler_task_runner_(std::move(scheduler_task_runner)), + quota_manager_proxy_(std::move(quota_manager_proxy)), + blob_storage_context_(std::move(blob_storage_context)), + cache_storage_(cache_storage), + storage_key_(storage_key), + owner_(owner) { + DCHECK(!storage_key_.origin().opaque()); + } + + virtual ~CacheLoader() = default; + + // Creates a CacheStorageCache with the given name. It does not attempt to + // load the backend, that happens lazily when the cache is used. + virtual std::unique_ptr<CacheStorageCache> CreateCache( + const std::string& cache_name, + int64_t cache_size, + int64_t cache_padding) = 0; + + // Deletes any pre-existing cache of the same name and then loads it. + virtual void PrepareNewCacheDestination(const std::string& cache_name, + CacheAndErrorCallback callback) = 0; + + // After the backend has been deleted, do any extra house keeping such as + // removing the cache's directory. + virtual void CleanUpDeletedCache(CacheStorageCache* cache) = 0; + + // Writes the cache index to disk if applicable. + virtual void WriteIndex(const CacheStorageIndex& index, + BoolCallback callback) = 0; + + // Loads the cache index from disk if applicable. + virtual void LoadIndex(CacheStorageIndexLoadCallback callback) = 0; + + // Called when CacheStorage has created a cache. Used to hold onto a handle to + // the cache if necessary. + virtual void NotifyCacheCreated(const std::string& cache_name, + CacheStorageCacheHandle cache_handle) {} + + // Notification that the cache for |cache_handle| has been doomed. If the + // loader is holding a handle to the cache, it should drop it now. + virtual void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) {} + + protected: + const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; + const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; + + // Owned by CacheStorage which owns this. This is guaranteed to outlive + // CacheLoader, but we store a reference to keep it alive for callbacks. + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; + + scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; + + // Raw pointer is safe because this object is owned by cache_storage_. + raw_ptr<CacheStorage> cache_storage_; + + blink::StorageKey storage_key_; + storage::mojom::CacheStorageOwner owner_; +}; + +// Creates memory-only ServiceWorkerCaches. Because these caches have no +// persistent storage it is not safe to free them from memory if they might be +// used again. Therefore this class holds a reference to each cache until the +// cache is doomed. +class CacheStorage::MemoryLoader : public CacheStorage::CacheLoader { + public: + MemoryLoader(base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + CacheStorage* cache_storage, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) + : CacheLoader(cache_task_runner, + std::move(scheduler_task_runner), + std::move(quota_manager_proxy), + std::move(blob_storage_context), + cache_storage, + storage_key, + owner) {} + + std::unique_ptr<CacheStorageCache> CreateCache( + const std::string& cache_name, + int64_t cache_size, + int64_t cache_padding) override { + return CacheStorageCache::CreateMemoryCache( + storage_key_, owner_, cache_name, cache_storage_, + scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_); + } + + void PrepareNewCacheDestination(const std::string& cache_name, + CacheAndErrorCallback callback) override { + std::unique_ptr<CacheStorageCache> cache = + CreateCache(cache_name, /*cache_size=*/0, /*cache_padding=*/0); + std::move(callback).Run(std::move(cache), CacheStorageError::kSuccess); + } + + void CleanUpDeletedCache(CacheStorageCache* cache) override {} + + void WriteIndex(const CacheStorageIndex& index, + BoolCallback callback) override { + std::move(callback).Run(true); + } + + void LoadIndex(CacheStorageIndexLoadCallback callback) override { + std::move(callback).Run(std::make_unique<CacheStorageIndex>()); + } + + void NotifyCacheCreated(const std::string& cache_name, + CacheStorageCacheHandle cache_handle) override { + DCHECK(!base::Contains(cache_handles_, cache_name)); + cache_handles_.insert(std::make_pair(cache_name, std::move(cache_handle))); + } + + void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override { + auto* impl = CacheStorageCache::From(cache_handle); + DCHECK(base::Contains(cache_handles_, impl->cache_name())); + cache_handles_.erase(impl->cache_name()); + } + + private: + typedef std::map<std::string, CacheStorageCacheHandle> CacheHandles; + ~MemoryLoader() override = default; + + // Keep a reference to each cache to ensure that it's not freed before the + // client calls CacheStorage::Delete or the CacheStorage is + // freed. + CacheHandles cache_handles_; +}; + +class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader { + public: + SimpleCacheLoader( + const base::FilePath& origin_path, + base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + CacheStorage* cache_storage, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) + : CacheLoader(cache_task_runner, + std::move(scheduler_task_runner), + std::move(quota_manager_proxy), + std::move(blob_storage_context), + cache_storage, + storage_key, + owner), + origin_path_(origin_path) {} + + std::unique_ptr<CacheStorageCache> CreateCache( + const std::string& cache_name, + int64_t cache_size, + int64_t cache_padding) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(base::Contains(cache_name_to_cache_dir_, cache_name)); + + std::string cache_dir = cache_name_to_cache_dir_[cache_name]; + base::FilePath cache_path = origin_path_.AppendASCII(cache_dir); + return CacheStorageCache::CreatePersistentCache( + storage_key_, owner_, cache_name, cache_storage_, cache_path, + scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_, + cache_size, cache_padding); + } + + void PrepareNewCacheDestination(const std::string& cache_name, + CacheAndErrorCallback callback) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + PostTaskAndReplyWithResult( + cache_task_runner_.get(), FROM_HERE, + base::BindOnce(&SimpleCacheLoader::PrepareNewCacheDirectoryInPool, + origin_path_), + base::BindOnce(&SimpleCacheLoader::PrepareNewCacheCreateCache, + weak_ptr_factory_.GetWeakPtr(), cache_name, + std::move(callback))); + } + + // Runs on the cache_task_runner_. + static std::tuple<CacheStorageError, std::string> + PrepareNewCacheDirectoryInPool(const base::FilePath& origin_path) { + std::string cache_dir; + base::FilePath cache_path; + do { + cache_dir = base::GenerateGUID(); + cache_path = origin_path.AppendASCII(cache_dir); + } while (base::PathExists(cache_path)); + + base::File::Error error = base::File::FILE_OK; + if (base::CreateDirectoryAndGetError(cache_path, &error)) { + return std::make_tuple(CacheStorageError::kSuccess, cache_dir); + } else { + CacheStorageError status = + error == base::File::FILE_ERROR_NO_SPACE + ? CacheStorageError::kErrorQuotaExceeded + : MakeErrorStorage(ErrorStorageType::kDidCreateNullCache); + return std::make_tuple(status, cache_dir); + } + } + + void PrepareNewCacheCreateCache( + const std::string& cache_name, + CacheAndErrorCallback callback, + const std::tuple<CacheStorageError, std::string>& result) { + const auto& [status, cache_dir] = result; + + if (status != CacheStorageError::kSuccess) { + std::move(callback).Run(nullptr, status); + return; + } + DCHECK(!cache_dir.empty()); + + cache_name_to_cache_dir_[cache_name] = cache_dir; + std::move(callback).Run(CreateCache(cache_name, CacheStorage::kSizeUnknown, + CacheStorage::kSizeUnknown), + CacheStorageError::kSuccess); + } + + void CleanUpDeletedCache(CacheStorageCache* cache) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(base::Contains(doomed_cache_to_path_, cache)); + + base::FilePath cache_path = + origin_path_.AppendASCII(doomed_cache_to_path_[cache]); + doomed_cache_to_path_.erase(cache); + + cache_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool, + cache_path)); + } + + static void CleanUpDeleteCacheDirInPool(const base::FilePath& cache_path) { + base::DeletePathRecursively(cache_path); + } + + void WriteIndex(const CacheStorageIndex& index, + BoolCallback callback) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // 1. Create the index file as a string. (WriteIndex) + // 2. Write the file to disk. (WriteIndexWriteToFileInPool) + + proto::CacheStorageIndex protobuf_index; + // GetURL().spec() is used here rather than Serialize() to ensure + // backwards compatibility with older data. The serializations are + // subtly different, e.g. Origin does not include a trailing "/". + // TODO(crbug.com/809329): Add a test for validating fields in the proto + // + // TODO(https://crbug.com/1199077): We need to serialize the entire + // `storage_key_` into the index file. + protobuf_index.set_origin(storage_key_.origin().GetURL().spec()); + + for (const auto& cache_metadata : index.ordered_cache_metadata()) { + DCHECK(base::Contains(cache_name_to_cache_dir_, cache_metadata.name)); + + proto::CacheStorageIndex::Cache* index_cache = protobuf_index.add_cache(); + index_cache->set_name(cache_metadata.name); + index_cache->set_cache_dir(cache_name_to_cache_dir_[cache_metadata.name]); + if (cache_metadata.size == CacheStorage::kSizeUnknown) + index_cache->clear_size(); + else + index_cache->set_size(cache_metadata.size); + index_cache->set_padding(cache_metadata.padding); + index_cache->set_padding_version( + CacheStorageCache::GetResponsePaddingVersion()); + } + + std::string serialized; + bool success = protobuf_index.SerializeToString(&serialized); + DCHECK(success); + + base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp"); + base::FilePath index_path = + origin_path_.AppendASCII(CacheStorage::kIndexFileName); + + PostTaskAndReplyWithResult( + cache_task_runner_.get(), FROM_HERE, + base::BindOnce(&SimpleCacheLoader::WriteIndexWriteToFileInPool, + tmp_path, index_path, serialized, quota_manager_proxy_, + storage_key_), + std::move(callback)); + } + + static bool WriteIndexWriteToFileInPool( + const base::FilePath& tmp_path, + const base::FilePath& index_path, + const std::string& data, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + const blink::StorageKey& storage_key) { + int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size()); + if (bytes_written != base::checked_cast<int>(data.size())) { + base::DeleteFile(tmp_path); + quota_manager_proxy->NotifyWriteFailed(storage_key); + return false; + } + + // Atomically rename the temporary index file to become the real one. + return base::ReplaceFile(tmp_path, index_path, nullptr); + } + + void LoadIndex(CacheStorageIndexLoadCallback callback) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + PostTaskAndReplyWithResult( + cache_task_runner_.get(), FROM_HERE, + base::BindOnce(&SimpleCacheLoader::ReadAndMigrateIndexInPool, + origin_path_, quota_manager_proxy_, storage_key_), + base::BindOnce(&SimpleCacheLoader::LoadIndexDidReadIndex, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + } + + void LoadIndexDidReadIndex(CacheStorageIndexLoadCallback callback, + proto::CacheStorageIndex protobuf_index) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + std::unique_ptr<std::set<std::string>> cache_dirs( + new std::set<std::string>); + + auto index = std::make_unique<CacheStorageIndex>(); + for (int i = 0, max = protobuf_index.cache_size(); i < max; ++i) { + const proto::CacheStorageIndex::Cache& cache = protobuf_index.cache(i); + DCHECK(cache.has_cache_dir()); + int64_t cache_size = + cache.has_size() ? cache.size() : CacheStorage::kSizeUnknown; + int64_t cache_padding; + if (cache.has_padding()) { + if (cache.has_padding_version() && + cache.padding_version() == + CacheStorageCache::GetResponsePaddingVersion()) { + cache_padding = cache.padding(); + } else { + // The padding algorithm version changed so set to unknown to force + // recalculation. + cache_padding = CacheStorage::kSizeUnknown; + } + } else { + cache_padding = CacheStorage::kSizeUnknown; + } + + index->Insert(CacheStorageIndex::CacheMetadata(cache.name(), cache_size, + cache_padding)); + cache_name_to_cache_dir_[cache.name()] = cache.cache_dir(); + cache_dirs->insert(cache.cache_dir()); + } + + cache_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&DeleteUnreferencedCachesInPool, origin_path_, + std::move(cache_dirs))); + std::move(callback).Run(std::move(index)); + } + + void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override { + auto* impl = CacheStorageCache::From(cache_handle); + DCHECK(base::Contains(cache_name_to_cache_dir_, impl->cache_name())); + auto iter = cache_name_to_cache_dir_.find(impl->cache_name()); + doomed_cache_to_path_[cache_handle.value()] = iter->second; + cache_name_to_cache_dir_.erase(iter); + } + + private: + friend class MigratedLegacyCacheDirectoryNameTest; + ~SimpleCacheLoader() override = default; + + // Iterates over the caches and deletes any directory not found in + // |cache_dirs|. Runs on cache_task_runner_ + static void DeleteUnreferencedCachesInPool( + const base::FilePath& cache_base_dir, + std::unique_ptr<std::set<std::string>> cache_dirs) { + base::FileEnumerator file_enum(cache_base_dir, false /* recursive */, + base::FileEnumerator::DIRECTORIES); + std::vector<base::FilePath> dirs_to_delete; + { + base::FilePath cache_path; + while (!(cache_path = file_enum.Next()).empty()) { + if (!base::Contains(*cache_dirs, cache_path.BaseName().AsUTF8Unsafe())) + dirs_to_delete.push_back(cache_path); + } + } + + for (const base::FilePath& cache_path : dirs_to_delete) + base::DeletePathRecursively(cache_path); + } + + // Runs on cache_task_runner_ + static proto::CacheStorageIndex ReadAndMigrateIndexInPool( + const base::FilePath& origin_path, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + const blink::StorageKey& storage_key) { + const base::FilePath index_path = + origin_path.AppendASCII(CacheStorage::kIndexFileName); + + proto::CacheStorageIndex index; + std::string body; + if (!base::ReadFileToString(index_path, &body) || + !index.ParseFromString(body)) + return proto::CacheStorageIndex(); + body.clear(); + + base::File::Info file_info; + base::Time index_last_modified; + if (GetFileInfo(index_path, &file_info)) + index_last_modified = file_info.last_modified; + bool index_modified = false; + + // Look for caches that have no cache_dir. Give any such caches a directory + // with a random name and move them there. Then, rewrite the index file. + // Additionally invalidate the size of any index entries where the cache was + // modified after the index (making it out-of-date). + for (int i = 0, max = index.cache_size(); i < max; ++i) { + const proto::CacheStorageIndex::Cache& cache = index.cache(i); + if (cache.has_cache_dir()) { + if (cache.has_size()) { + base::FilePath cache_dir = origin_path.AppendASCII(cache.cache_dir()); + if (!GetFileInfo(cache_dir, &file_info) || + index_last_modified <= file_info.last_modified) { + // Index is older than this cache, so invalidate index entries that + // may change as a result of cache operations. + index.mutable_cache(i)->clear_size(); + } + } + } else { + // Find a new home for the cache. + base::FilePath legacy_cache_path = + origin_path.AppendASCII(HexedHash(cache.name())); + std::string cache_dir; + base::FilePath cache_path; + do { + cache_dir = base::GenerateGUID(); + cache_path = origin_path.AppendASCII(cache_dir); + } while (base::PathExists(cache_path)); + + if (!base::Move(legacy_cache_path, cache_path)) { + // If the move fails then the cache is in a bad state. Return an empty + // index so that the CacheStorage can start fresh. The unreferenced + // caches will be discarded later in initialization. + return proto::CacheStorageIndex(); + } + + index.mutable_cache(i)->set_cache_dir(cache_dir); + index.mutable_cache(i)->clear_size(); + index_modified = true; + } + } + + if (index_modified) { + base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp"); + if (!index.SerializeToString(&body) || + !WriteIndexWriteToFileInPool(tmp_path, index_path, body, + std::move(quota_manager_proxy), + storage_key)) { + return proto::CacheStorageIndex(); + } + } + + return index; + } + + const base::FilePath origin_path_; + std::map<std::string, std::string> cache_name_to_cache_dir_; + std::map<CacheStorageCache*, std::string> doomed_cache_to_path_; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_{this}; +}; + +CacheStorage::CacheStorage( + const base::FilePath& path, + bool memory_only, + base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + CacheStorageManager* cache_storage_manager, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) + : storage_key_(storage_key), + memory_only_(memory_only), + scheduler_( + new CacheStorageScheduler(CacheStorageSchedulerClient::kStorage, + scheduler_task_runner)), + origin_path_(path), + cache_task_runner_(cache_task_runner), + quota_manager_proxy_(quota_manager_proxy), + blob_storage_context_(std::move(blob_storage_context)), + owner_(owner), + cache_storage_manager_(cache_storage_manager) { + if (memory_only) { + cache_loader_ = base::WrapUnique<CacheLoader>(new MemoryLoader( + cache_task_runner_.get(), std::move(scheduler_task_runner), + quota_manager_proxy, blob_storage_context_, this, storage_key, owner)); + return; + } + + cache_loader_ = base::WrapUnique<CacheLoader>(new SimpleCacheLoader( + origin_path_, cache_task_runner_.get(), std::move(scheduler_task_runner), + quota_manager_proxy, blob_storage_context_, this, storage_key, owner)); + +#if BUILDFLAG(IS_ANDROID) + app_status_listener_ = + base::android::ApplicationStatusListener::New(base::BindRepeating( + &CacheStorage::OnApplicationStateChange, weak_factory_.GetWeakPtr())); +#endif +} + +CacheStorage::~CacheStorage() { + FlushIndexIfDirty(); +} + +CacheStorageHandle CacheStorage::CreateHandle() { + return CacheStorageHandle(weak_factory_.GetWeakPtr()); +} + +void CacheStorage::AddHandleRef() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + handle_ref_count_ += 1; +} + +void CacheStorage::DropHandleRef() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GT(handle_ref_count_, 0U); + handle_ref_count_ -= 1; + if (!handle_ref_count_ && cache_storage_manager_) { + ReleaseUnreferencedCaches(); + cache_storage_manager_->CacheStorageUnreferenced(this, storage_key_, + owner_); + } +} + +void CacheStorage::Init() { + if (!initialized_) + LazyInit(); +} + +void CacheStorage::OpenCache(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + // TODO: Hold a handle to this CacheStorage instance while executing + // operations to better support use by internal code that may + // start a single operation without explicitly maintaining a + // handle. + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kOpen, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::OpenCacheImpl, weak_factory_.GetWeakPtr(), cache_name, + trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::HasCache(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kHas, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::HasCacheImpl, weak_factory_.GetWeakPtr(), cache_name, + trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::DoomCache(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kDelete, CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::DoomCacheImpl, weak_factory_.GetWeakPtr(), cache_name, + trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::EnumerateCaches(int64_t trace_id, + EnumerateCachesCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::EnumerateCachesImpl, weak_factory_.GetWeakPtr(), + trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::MatchCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(), cache_name, + std::move(request), std::move(match_options), priority, trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::MatchAllCaches( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kMatchAll, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::MatchAllCachesImpl, weak_factory_.GetWeakPtr(), + std::move(request), std::move(match_options), priority, trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::WriteToCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + CacheStorage::ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + quota_manager_proxy_->NotifyStorageAccessed( + storage_key_, StorageType::kTemporary, base::Time::Now()); + + // Note, this is a shared operation since it only reads CacheStorage data. + // The CacheStorageCache is responsible for making its put operation + // exclusive. + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kPut, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::WriteToCacheImpl, weak_factory_.GetWeakPtr(), + cache_name, std::move(request), std::move(response), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::GetSizeThenCloseAllCaches(SizeCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + // Note, this is a shared operation since it only reads CacheStorage data. + // The CacheStorageCache is responsible for making its close operation + // exclusive. + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kSizeThenClose, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::GetSizeThenCloseAllCachesImpl, + weak_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::Size(CacheStorage::SizeCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!initialized_) + LazyInit(); + + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::SizeImpl, weak_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::ResetManager() { + cache_storage_manager_ = nullptr; +} + +void CacheStorage::NotifyCacheContentChanged(const std::string& cache_name) { + if (cache_storage_manager_) + cache_storage_manager_->NotifyCacheContentChanged(storage_key_, cache_name); +} + +void CacheStorage::ScheduleWriteIndex() { + // These values are chosen to be equal or greater than the simple disk_cache + // index write delays. We want the cache_storage index to be written last. + static const int64_t kWriteIndexDelayMilliseconds = 20050; + static const int64_t kWriteIndexBackgroundDelayMilliseconds = 150; + int64_t delay_ms = app_on_background_ ? kWriteIndexBackgroundDelayMilliseconds + : kWriteIndexDelayMilliseconds; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + index_write_task_.Reset(base::BindOnce(&CacheStorage::WriteIndex, + weak_factory_.GetWeakPtr(), + base::DoNothing())); + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, index_write_task_.callback(), base::Milliseconds(delay_ms)); +} + +void CacheStorage::WriteIndex(base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kWriteIndex, + CacheStorageSchedulerPriority::kNormal, + base::BindOnce( + &CacheStorage::WriteIndexImpl, weak_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); +} + +void CacheStorage::WriteIndexImpl(base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(scheduler_->IsRunningExclusiveOperation()); + cache_loader_->WriteIndex(*cache_index_, std::move(callback)); +} + +bool CacheStorage::InitiateScheduledIndexWriteForTest( + base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (index_write_pending()) { + index_write_task_.Cancel(); + WriteIndex(std::move(callback)); + return true; + } + std::move(callback).Run(true /* success */); + return false; +} + +void CacheStorage::CacheSizeUpdated(const CacheStorageCache* cache) { + // Should not be called for doomed caches. + DCHECK( + !base::Contains(doomed_caches_, const_cast<CacheStorageCache*>(cache))); + DCHECK_NE(cache->cache_padding(), kSizeUnknown); + bool size_changed = + cache_index_->SetCacheSize(cache->cache_name(), cache->cache_size()); + bool padding_changed = cache_index_->SetCachePadding(cache->cache_name(), + cache->cache_padding()); + if (size_changed || padding_changed) + ScheduleWriteIndex(); +} + +void CacheStorage::ReleaseUnreferencedCaches() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (auto& entry : cache_map_) { + if (entry.second && entry.second->IsUnreferenced()) + entry.second.reset(); + } +} + +void CacheStorage::CacheUnreferenced(CacheStorageCache* cache) { + DCHECK(cache); + DCHECK(cache->IsUnreferenced()); + auto doomed_caches_it = doomed_caches_.find(cache); + if (doomed_caches_it != doomed_caches_.end()) { + // The last reference to a doomed cache is gone, perform clean up. + DeleteCacheFinalize(cache); + return; + } + + // Opportunistically keep warmed caches open when the CacheStorage is + // still actively referenced. Repeatedly opening and closing simple + // disk_cache backends can be quite slow. This is easy to trigger when + // a site uses caches.match() frequently because the a Cache object is + // never exposed to script to explicitly hold the backend open. + if (handle_ref_count_) + return; + + // The CacheStorage is not actively being referenced. Close the cache + // immediately. + auto cache_map_it = cache_map_.find(cache->cache_name()); + DCHECK(cache_map_it != cache_map_.end()); + + cache_map_it->second.reset(); +} + +CacheStorageSchedulerId CacheStorage::StartAsyncOperationForTesting() { + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, + CacheStorageSchedulerPriority::kNormal, base::DoNothing()); + return id; +} + +void CacheStorage::CompleteAsyncOperationForTesting( + CacheStorageSchedulerId id) { + scheduler_->CompleteOperationAndRunNext(id); +} + +// Init is run lazily so that it is called on the proper MessageLoop. +void CacheStorage::LazyInit() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!initialized_); + + if (initializing_) + return; + + DCHECK(!scheduler_->ScheduledOperations()); + + initializing_ = true; + init_id_ = scheduler_->CreateId(); + scheduler_->ScheduleOperation( + init_id_, CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kInit, CacheStorageSchedulerPriority::kNormal, + base::BindOnce(&CacheStorage::LazyInitImpl, weak_factory_.GetWeakPtr())); +} + +void CacheStorage::LazyInitImpl() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!initialized_); + DCHECK(initializing_); + + // 1. Get the cache index (async call) + // 2. For each cache name, load the cache (async call) + // 3. Once each load is complete, update the map variables. + // 4. Call the list of waiting callbacks. + + DCHECK(scheduler_->IsRunningExclusiveOperation()); + cache_loader_->LoadIndex(base::BindOnce(&CacheStorage::LazyInitDidLoadIndex, + weak_factory_.GetWeakPtr())); +} + +void CacheStorage::LazyInitDidLoadIndex( + std::unique_ptr<CacheStorageIndex> index) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(cache_map_.empty()); + + for (const auto& cache_metadata : index->ordered_cache_metadata()) { + cache_map_.insert(std::make_pair(cache_metadata.name, nullptr)); + } + + DCHECK(!cache_index_); + cache_index_ = std::move(index); + + initializing_ = false; + initialized_ = true; + + scheduler_->CompleteOperationAndRunNext(init_id_); +} + +void CacheStorage::OpenCacheImpl(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback) { + TRACE_EVENT_WITH_FLOW1("CacheStorage", "CacheStorage::OpenCacheImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "cache_name", cache_name); + CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); + if (cache_handle.value()) { + std::move(callback).Run(std::move(cache_handle), + CacheStorageError::kSuccess); + return; + } + + DCHECK(scheduler_->IsRunningExclusiveOperation()); + cache_loader_->PrepareNewCacheDestination( + cache_name, base::BindOnce(&CacheStorage::CreateCacheDidCreateCache, + weak_factory_.GetWeakPtr(), cache_name, + trace_id, std::move(callback))); +} + +void CacheStorage::CreateCacheDidCreateCache( + const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback, + std::unique_ptr<CacheStorageCache> cache, + CacheStorageError status) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + TRACE_EVENT_WITH_FLOW0("CacheStorage", + "CacheStorage::CreateCacheDidCreateCache", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + + UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult", + static_cast<bool>(cache)); + + if (status != CacheStorageError::kSuccess) { + std::move(callback).Run(CacheStorageCacheHandle(), status); + return; + } + + CacheStorageCache* cache_ptr = cache.get(); + + cache_map_.insert(std::make_pair(cache_name, std::move(cache))); + cache_index_->Insert(CacheStorageIndex::CacheMetadata( + cache_name, cache_ptr->cache_size(), cache_ptr->cache_padding())); + + CacheStorageCacheHandle handle = cache_ptr->CreateHandle(); + index_write_task_.Cancel(); + cache_loader_->WriteIndex( + *cache_index_, + base::BindOnce(&CacheStorage::CreateCacheDidWriteIndex, + weak_factory_.GetWeakPtr(), std::move(callback), + cache_ptr->CreateHandle(), trace_id)); + + cache_loader_->NotifyCacheCreated(cache_name, std::move(handle)); + if (cache_storage_manager_) + cache_storage_manager_->NotifyCacheListChanged(storage_key_); +} + +void CacheStorage::CreateCacheDidWriteIndex( + CacheAndErrorCallback callback, + CacheStorageCacheHandle cache_handle, + int64_t trace_id, + bool success) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(cache_handle.value()); + + TRACE_EVENT_WITH_FLOW0("CacheStorage", + "CacheStorage::CreateCacheDidWriteIndex", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + + // TODO(jkarlin): Handle !success. + + std::move(callback).Run(std::move(cache_handle), CacheStorageError::kSuccess); +} + +void CacheStorage::HasCacheImpl(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback) { + TRACE_EVENT_WITH_FLOW1("CacheStorage", "CacheStorage::HasCacheImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "cache_name", cache_name); + bool has_cache = base::Contains(cache_map_, cache_name); + std::move(callback).Run(has_cache, CacheStorageError::kSuccess); +} + +void CacheStorage::DoomCacheImpl(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback) { + TRACE_EVENT_WITH_FLOW1("CacheStorage", "CacheStorage::DoomCacheImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "cache_name", cache_name); + CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); + if (!cache_handle.value()) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), CacheStorageError::kErrorNotFound)); + return; + } + + DCHECK(scheduler_->IsRunningExclusiveOperation()); + CacheStorageCache::From(cache_handle)->SetObserver(nullptr); + cache_index_->DoomCache(cache_name); + index_write_task_.Cancel(); + cache_loader_->WriteIndex( + *cache_index_, + base::BindOnce(&CacheStorage::DeleteCacheDidWriteIndex, + weak_factory_.GetWeakPtr(), std::move(cache_handle), + std::move(callback), trace_id)); +} + +void CacheStorage::DeleteCacheDidWriteIndex( + CacheStorageCacheHandle cache_handle, + ErrorCallback callback, + int64_t trace_id, + bool success) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto* impl = CacheStorageCache::From(cache_handle); + + TRACE_EVENT_WITH_FLOW0("CacheStorage", + "CacheStorage::DeleteCacheDidWriteIndex", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + + if (!success) { + // Undo any changes if the index couldn't be written to disk. + cache_index_->RestoreDoomedCache(); + impl->SetObserver(this); + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kDeleteCacheFailed)); + return; + } + + cache_index_->FinalizeDoomedCache(); + + auto map_iter = cache_map_.find(impl->cache_name()); + DCHECK(map_iter != cache_map_.end()); + + doomed_caches_.insert( + std::make_pair(map_iter->second.get(), std::move(map_iter->second))); + cache_map_.erase(map_iter); + + cache_loader_->NotifyCacheDoomed(std::move(cache_handle)); + if (cache_storage_manager_) + cache_storage_manager_->NotifyCacheListChanged(storage_key_); + + std::move(callback).Run(CacheStorageError::kSuccess); +} + +// Call this once the last handle to a doomed cache is gone. It's okay if this +// doesn't get to complete before shutdown, the cache will be removed from disk +// on next startup in that case. +void CacheStorage::DeleteCacheFinalize(CacheStorageCache* doomed_cache) { + doomed_cache->Size(base::BindOnce(&CacheStorage::DeleteCacheDidGetSize, + weak_factory_.GetWeakPtr(), doomed_cache)); +} + +void CacheStorage::DeleteCacheDidGetSize(CacheStorageCache* doomed_cache, + int64_t cache_size) { + quota_manager_proxy_->NotifyStorageModified( + CacheStorageQuotaClient::GetClientTypeFromOwner(owner_), storage_key_, + StorageType::kTemporary, -cache_size, base::Time::Now(), + base::SequencedTaskRunnerHandle::Get(), base::DoNothing()); + + cache_loader_->CleanUpDeletedCache(doomed_cache); + auto doomed_caches_iter = doomed_caches_.find(doomed_cache); + DCHECK(doomed_caches_iter != doomed_caches_.end()); + doomed_caches_.erase(doomed_caches_iter); +} + +void CacheStorage::EnumerateCachesImpl(int64_t trace_id, + EnumerateCachesCallback callback) { + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorage::EnumerateCachesImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + + std::vector<std::string> list; + + for (const auto& metadata : cache_index_->ordered_cache_metadata()) { + list.push_back(metadata.name); + } + + std::move(callback).Run(std::move(list)); +} + +void CacheStorage::MatchCacheImpl( + const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + TRACE_EVENT_WITH_FLOW2( + "CacheStorage", "CacheStorage::MatchCacheImpl", TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "cache_name", + cache_name, "request", CacheStorageTracedValue(request)); + + CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); + + if (!cache_handle.value()) { + std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound, + nullptr); + return; + } + + // Pass the cache handle along to the callback to keep the cache open until + // match is done. + CacheStorageCache* cache_ptr = cache_handle.value(); + cache_ptr->Match( + std::move(request), std::move(match_options), priority, trace_id, + base::BindOnce(&CacheStorage::MatchCacheDidMatch, + weak_factory_.GetWeakPtr(), std::move(cache_handle), + trace_id, std::move(callback))); +} + +void CacheStorage::MatchCacheDidMatch( + CacheStorageCacheHandle cache_handle, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback, + CacheStorageError error, + blink::mojom::FetchAPIResponsePtr response) { + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorage::MatchCacheDidMatch", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + std::move(callback).Run(error, std::move(response)); +} + +void CacheStorage::MatchAllCachesImpl( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorage::MatchAllCachesImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + + std::vector<CacheMatchResponse>* match_responses = + new std::vector<CacheMatchResponse>(cache_index_->num_entries()); + + base::RepeatingClosure barrier_closure = base::BarrierClosure( + cache_index_->num_entries(), + base::BindOnce( + &CacheStorage::MatchAllCachesDidMatchAll, weak_factory_.GetWeakPtr(), + base::WrapUnique(match_responses), trace_id, std::move(callback))); + + size_t idx = 0; + for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) { + CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name); + DCHECK(cache_handle.value()); + + CacheStorageCache* cache_ptr = cache_handle.value(); + cache_ptr->Match( + BackgroundFetchSettledFetch::CloneRequest(request), + match_options ? match_options->Clone() : nullptr, priority, trace_id, + base::BindOnce(&CacheStorage::MatchAllCachesDidMatch, + weak_factory_.GetWeakPtr(), std::move(cache_handle), + &match_responses->at(idx), barrier_closure, trace_id)); + idx++; + } +} + +void CacheStorage::MatchAllCachesDidMatch( + CacheStorageCacheHandle cache_handle, + CacheMatchResponse* out_match_response, + const base::RepeatingClosure& barrier_closure, + int64_t trace_id, + CacheStorageError error, + blink::mojom::FetchAPIResponsePtr response) { + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorage::MatchAllCachesDidMatch", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + out_match_response->error = error; + out_match_response->response = std::move(response); + barrier_closure.Run(); +} + +void CacheStorage::MatchAllCachesDidMatchAll( + std::unique_ptr<std::vector<CacheMatchResponse>> match_responses, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + TRACE_EVENT_WITH_FLOW0("CacheStorage", + "CacheStorage::MatchAllCachesDidMatchAll", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + for (CacheMatchResponse& match_response : *match_responses) { + if (match_response.error == CacheStorageError::kErrorNotFound) + continue; + std::move(callback).Run(match_response.error, + std::move(match_response.response)); + return; + } + std::move(callback).Run(CacheStorageError::kErrorNotFound, nullptr); +} + +void CacheStorage::WriteToCacheImpl(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + CacheStorage::ErrorCallback callback) { + TRACE_EVENT_WITH_FLOW2("CacheStorage", "CacheStorage::WriteToCacheImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "cache_name", cache_name, "request", + CacheStorageTracedValue(request)); + + CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); + + if (!cache_handle.value()) { + std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound); + return; + } + + CacheStorageCache* cache_ptr = cache_handle.value(); + DCHECK(cache_ptr); + + cache_ptr->Put(std::move(request), std::move(response), trace_id, + std::move(callback)); +} + +CacheStorageCacheHandle CacheStorage::GetLoadedCache( + const std::string& cache_name) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(initialized_); + + auto map_iter = cache_map_.find(cache_name); + if (map_iter == cache_map_.end()) + return CacheStorageCacheHandle(); + + CacheStorageCache* cache = map_iter->second.get(); + + if (!cache) { + const CacheStorageIndex::CacheMetadata* metadata = + cache_index_->GetMetadata(cache_name); + DCHECK(metadata); + std::unique_ptr<CacheStorageCache> new_cache = cache_loader_->CreateCache( + cache_name, metadata->size, metadata->padding); + CacheStorageCache* cache_ptr = new_cache.get(); + map_iter->second = std::move(new_cache); + + return cache_ptr->CreateHandle(); + } + + return cache->CreateHandle(); +} + +void CacheStorage::SizeRetrievedFromCache(CacheStorageCacheHandle cache_handle, + base::OnceClosure closure, + int64_t* accumulator, + int64_t size) { + auto* impl = CacheStorageCache::From(cache_handle); + if (doomed_caches_.find(impl) == doomed_caches_.end()) { + cache_index_->SetCacheSize(impl->cache_name(), impl->cache_size()); + cache_index_->SetCachePadding(impl->cache_name(), impl->cache_padding()); + } + *accumulator += (impl->cache_size() + impl->cache_padding()); + std::move(closure).Run(); +} + +void CacheStorage::GetSizeThenCloseAllCachesImpl(SizeCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(initialized_); + + std::unique_ptr<int64_t> accumulator(new int64_t(0)); + int64_t* accumulator_ptr = accumulator.get(); + + base::RepeatingClosure barrier_closure = base::BarrierClosure( + cache_index_->num_entries() + doomed_caches_.size(), + base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator), + std::move(callback))); + + for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) { + auto cache_handle = GetLoadedCache(cache_metadata.name); + CacheStorageCache* cache = CacheStorageCache::From(cache_handle); + cache->GetSizeThenClose(base::BindOnce( + &CacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(), + std::move(cache_handle), barrier_closure, accumulator_ptr)); + } + + for (const auto& cache_it : doomed_caches_) { + CacheStorageCache* cache = cache_it.first; + cache->GetSizeThenClose(base::BindOnce( + &CacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(), + cache->CreateHandle(), barrier_closure, accumulator_ptr)); + } +} + +void CacheStorage::SizeImpl(SizeCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(initialized_); + + if (cache_index_->GetPaddedStorageSize() != kSizeUnknown) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + cache_index_->GetPaddedStorageSize())); + return; + } + + std::unique_ptr<int64_t> accumulator(new int64_t(0)); + int64_t* accumulator_ptr = accumulator.get(); + + base::RepeatingClosure barrier_closure = base::BarrierClosure( + cache_index_->num_entries(), + base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator), + std::move(callback))); + + for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) { + if (cache_metadata.size != CacheStorage::kSizeUnknown && + cache_metadata.padding != CacheStorage::kSizeUnknown) { + *accumulator_ptr += (cache_metadata.size + cache_metadata.padding); + barrier_closure.Run(); + continue; + } + CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name); + CacheStorageCache* cache = CacheStorageCache::From(cache_handle); + cache->Size(base::BindOnce( + &CacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(), + std::move(cache_handle), barrier_closure, accumulator_ptr)); + } +} + +void CacheStorage::FlushIndexIfDirty() { + if (!index_write_pending()) + return; + index_write_task_.Cancel(); + cache_loader_->WriteIndex(*cache_index_, base::DoNothing()); +} + +#if BUILDFLAG(IS_ANDROID) +void CacheStorage::OnApplicationStateChange( + base::android::ApplicationState state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { + app_on_background_ = false; + } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) { + app_on_background_ = true; + FlushIndexIfDirty(); + } +} +#endif } // namespace content
diff --git a/content/browser/cache_storage/cache_storage.h b/content/browser/cache_storage/cache_storage.h index 6c51470..c2826cc 100644 --- a/content/browser/cache_storage/cache_storage.h +++ b/content/browser/cache_storage/cache_storage.h
@@ -7,26 +7,64 @@ #include <stdint.h> +#include <map> #include <memory> #include <string> #include <vector> #include "base/callback.h" +#include "base/files/file_path.h" +#include "base/gtest_prod_util.h" +#include "base/memory/memory_pressure_listener.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "build/build_config.h" +#include "components/services/storage/public/mojom/blob_storage_context.mojom.h" +#include "components/services/storage/public/mojom/cache_storage_control.mojom.h" +#include "content/browser/cache_storage/blob_storage_context_wrapper.h" #include "content/browser/cache_storage/cache_storage_cache.h" +#include "content/browser/cache_storage/cache_storage_cache_observer.h" #include "content/browser/cache_storage/cache_storage_handle.h" +#include "content/browser/cache_storage/cache_storage_manager.h" +#include "content/browser/cache_storage/cache_storage_scheduler_types.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "storage/browser/quota/quota_manager.h" #include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h" +#if BUILDFLAG(IS_ANDROID) +#include "base/android/application_status_listener.h" +#endif + +namespace base { +class SequencedTaskRunner; +} + namespace content { +class CacheStorageIndex; +class CacheStorageScheduler; +class CacheStorageManager; + +namespace cache_storage_manager_unittest { +class CacheStorageManagerTest; +FORWARD_DECLARE_TEST(CacheStorageManagerTest, PersistedCacheKeyUsed); +FORWARD_DECLARE_TEST(CacheStorageManagerTest, PutResponseWithExistingFileTest); +FORWARD_DECLARE_TEST(CacheStorageManagerTest, TestErrorInitializingCache); +} // namespace cache_storage_manager_unittest + +// TODO(jkarlin): Constrain the total bytes used per storage key. // CacheStorage holds the set of caches for a given StorageKey. It is // owned by the CacheStorageManager. This class expects to be run // on the IO thread. The asynchronous methods are executed serially. -class CONTENT_EXPORT CacheStorage { +class CONTENT_EXPORT CacheStorage : public CacheStorageCacheObserver { public: constexpr static int64_t kSizeUnknown = -1; + using SizeCallback = base::OnceCallback<void(int64_t)>; + using BoolAndErrorCallback = base::OnceCallback<void(bool, blink::mojom::CacheStorageError)>; using ErrorCallback = @@ -37,80 +75,321 @@ using EnumerateCachesCallback = base::OnceCallback<void(std::vector<std::string> cache_names)>; + static const char kIndexFileName[]; + + CacheStorage(const base::FilePath& origin_path, + bool memory_only, + base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + CacheStorageManager* cache_storage_manager, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner); + + CacheStorage(const CacheStorage&) = delete; + CacheStorage& operator=(const CacheStorage&) = delete; + + // Any unfinished asynchronous operations may not complete or call their + // callbacks. + virtual ~CacheStorage(); + // Creates a new handle to this CacheStorage instance. Each handle represents // a signal that the CacheStorage is in active use and should avoid cleaning // up resources, if possible. However, there are some cases, such as a // user-initiated storage wipe, that will forcibly delete the CacheStorage // instance. Therefore the handle should be treated as a weak pointer that // needs to be tested for existence before use. - virtual CacheStorageHandle CreateHandle() = 0; - virtual void AddHandleRef() = 0; - virtual void DropHandleRef() = 0; + CacheStorageHandle CreateHandle(); + + // These methods are called by the CacheStorageHandle to track the number + // of outstanding references. + void AddHandleRef(); + void DropHandleRef(); + void AssertUnreferenced() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!handle_ref_count_); + } // Explicitly begin initialization if it has not already been triggered. - virtual void Init() = 0; + void Init(); // Get the cache for the given key. If the cache is not found it is // created. The CacheStorgeCacheHandle in the callback prolongs the lifetime // of the cache. Once all handles to a cache are deleted the cache is deleted. // The cache will also be deleted in the CacheStorage's destructor so be sure // to check the handle's value before using it. - virtual void OpenCache(const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback) = 0; + void OpenCache(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback); // Calls the callback with whether or not the cache exists. - virtual void HasCache(const std::string& cache_name, - int64_t trace_id, - BoolAndErrorCallback callback) = 0; + void HasCache(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback); // Deletes the cache if it exists. If it doesn't exist, // blink::mojom::CacheStorageError::kErrorNotFound is returned. Any // existing CacheStorageCacheHandle(s) to the cache will remain valid but // future CacheStorage operations won't be able to access the cache. The cache // isn't actually erased from disk until the last handle is dropped. - virtual void DoomCache(const std::string& cache_name, - int64_t trace_id, - ErrorCallback callback) = 0; + void DoomCache(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback); // Calls the callback with the existing cache names. - virtual void EnumerateCaches(int64_t trace_id, - EnumerateCachesCallback callback) = 0; + void EnumerateCaches(int64_t trace_id, EnumerateCachesCallback callback); // Calls match on the cache with the given |cache_name|. - virtual void MatchCache(const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) = 0; + void MatchCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback); // Calls match on all of the caches in parallel, calling |callback| with the // response from the first cache (in order of cache creation) to have the // entry. If no response is found then |callback| is called with // blink::mojom::CacheStorageError::kErrorNotFound. - virtual void MatchAllCaches(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) = 0; + void MatchAllCaches(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback); // Puts the request/response pair in the cache. - virtual void WriteToCache(const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - ErrorCallback callback) = 0; + void WriteToCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback); + + // Sums the sizes of each cache and closes them. Runs |callback| with the + // size. The sizes include any doomed caches and will also force close all + // caches even if there are existing handles to them. + void GetSizeThenCloseAllCaches(SizeCallback callback); + + // The size of all of the storage key's contents. This value should be used as + // an estimate only since the cache may be modified at any time. + void Size(SizeCallback callback); + + // The functions below are for tests to verify that the operations run + // serially. + CacheStorageSchedulerId StartAsyncOperationForTesting(); + void CompleteAsyncOperationForTesting(CacheStorageSchedulerId id); + + // Removes the manager reference. Called before this storage is deleted by the + // manager, since it is removed from manager's storage map before deleting. + void ResetManager(); + + // CacheStorageCacheObserver: + void CacheSizeUpdated(const CacheStorageCache* cache) override; + + // Destroy any CacheStorageCache instances that are not currently referenced + // by a CacheStorageCacheHandle. + void ReleaseUnreferencedCaches(); + + static CacheStorage* From(const CacheStorageHandle& handle) { + return static_cast<CacheStorage*>(handle.value()); + } // The immutable StorageKey of the CacheStorage. const blink::StorageKey storage_key() const { return storage_key_; } protected: - explicit CacheStorage(const blink::StorageKey& storage_key); - virtual ~CacheStorage() = default; + // Virtual for testing + virtual void CacheUnreferenced(CacheStorageCache* cache); + + private: + friend class CacheStorageCache; + friend class cache_storage_manager_unittest::CacheStorageManagerTest; + FRIEND_TEST_ALL_PREFIXES( + cache_storage_manager_unittest::CacheStorageManagerTest, + PersistedCacheKeyUsed); + FRIEND_TEST_ALL_PREFIXES( + cache_storage_manager_unittest::CacheStorageManagerTest, + PutResponseWithExistingFileTest); + FRIEND_TEST_ALL_PREFIXES( + cache_storage_manager_unittest::CacheStorageManagerTest, + TestErrorInitializingCache); + class CacheLoader; + class MemoryLoader; + class SimpleCacheLoader; + struct CacheMatchResponse; + + typedef std::map<std::string, std::unique_ptr<CacheStorageCache>> CacheMap; + + // Generate a new padding key. For testing only and *not thread safe*. + static void GenerateNewKeyForTesting(); + + // Returns a CacheStorageCacheHandle for the given name if the name is known. + // If the CacheStorageCache has been deleted, creates a new one. + CacheStorageCacheHandle GetLoadedCache(const std::string& cache_name); + + // Initializer and its callback are below. + void LazyInit(); + void LazyInitImpl(); + void LazyInitDidLoadIndex(std::unique_ptr<CacheStorageIndex> index); + + // The Open and CreateCache callbacks are below. + void OpenCacheImpl(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback); + void CreateCacheDidCreateCache(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback, + std::unique_ptr<CacheStorageCache> cache, + blink::mojom::CacheStorageError status); + void CreateCacheDidWriteIndex(CacheAndErrorCallback callback, + CacheStorageCacheHandle cache_handle, + int64_t trace_id, + bool success); + + // The HasCache callbacks are below. + void HasCacheImpl(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback); + + // The DeleteCache callbacks are below. + void DoomCacheImpl(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback); + void DeleteCacheDidWriteIndex(CacheStorageCacheHandle cache_handle, + ErrorCallback callback, + int64_t trace_id, + bool success); + void DeleteCacheFinalize(CacheStorageCache* doomed_cache); + void DeleteCacheDidGetSize(CacheStorageCache* doomed_cache, + int64_t cache_size); + void DeleteCacheDidCleanUp(bool success); + + // The EnumerateCache callbacks are below. + void EnumerateCachesImpl(int64_t trace_id, EnumerateCachesCallback callback); + + // The MatchCache callbacks are below. + void MatchCacheImpl(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback); + void MatchCacheDidMatch(CacheStorageCacheHandle cache_handle, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback, + blink::mojom::CacheStorageError error, + blink::mojom::FetchAPIResponsePtr response); + + // The MatchAllCaches callbacks are below. + void MatchAllCachesImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback); + void MatchAllCachesDidMatch(CacheStorageCacheHandle cache_handle, + CacheMatchResponse* out_match_response, + const base::RepeatingClosure& barrier_closure, + int64_t trace_id, + blink::mojom::CacheStorageError error, + blink::mojom::FetchAPIResponsePtr response); + void MatchAllCachesDidMatchAll( + std::unique_ptr<std::vector<CacheMatchResponse>> match_responses, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback); + + // WriteToCache callbacks. + void WriteToCacheImpl(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback); + + void GetSizeThenCloseAllCachesImpl(SizeCallback callback); + + void SizeImpl(SizeCallback callback); + void SizeRetrievedFromCache(CacheStorageCacheHandle cache_handle, + base::OnceClosure closure, + int64_t* accumulator, + int64_t size); + + void NotifyCacheContentChanged(const std::string& cache_name); + + void ScheduleWriteIndex(); + void WriteIndex(base::OnceCallback<void(bool)> callback); + void WriteIndexImpl(base::OnceCallback<void(bool)> callback); + bool index_write_pending() const { return !index_write_task_.IsCancelled(); } + // Start a scheduled index write immediately. Returns true if a write was + // scheduled, or false if not. + bool InitiateScheduledIndexWriteForTest( + base::OnceCallback<void(bool)> callback); + + void FlushIndexIfDirty(); + +#if BUILDFLAG(IS_ANDROID) + void OnApplicationStateChange(base::android::ApplicationState state); +#endif // The StorageKey that this CacheStorage is associated with. const blink::StorageKey storage_key_; + + // Whether or not we've loaded the list of cache names into memory. + bool initialized_ = false; + bool initializing_ = false; + + // True if the backend is supposed to reside in memory only. + bool memory_only_; + + // The pending operation scheduler. + std::unique_ptr<CacheStorageScheduler> scheduler_; + + // The map of cache names to CacheStorageCache objects. + CacheMap cache_map_; + + // Caches that have been deleted but must still be held onto until all handles + // have been released. + std::map<CacheStorageCache*, std::unique_ptr<CacheStorageCache>> + doomed_caches_; + + // The cache index data. + std::unique_ptr<CacheStorageIndex> cache_index_; + + // The file path for this CacheStorage. + base::FilePath origin_path_; + + // The TaskRunner to run file IO on. + scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; + + // Performs backend specific operations (memory vs disk). + std::unique_ptr<CacheLoader> cache_loader_; + + // The quota manager. + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; + + // An IO thread bound wrapper for storage.mojom.BlobStorageContext. + scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; + + // The owner that this CacheStorage is associated with. + storage::mojom::CacheStorageOwner owner_; + + CacheStorageSchedulerId init_id_ = -1; + + // The manager that owns this cache storage. Only set to null by + // RemoveManager() when this cache storage is being deleted. + raw_ptr<CacheStorageManager> cache_storage_manager_; + + base::CancelableOnceClosure index_write_task_; + size_t handle_ref_count_ = 0; + +#if BUILDFLAG(IS_ANDROID) + std::unique_ptr<base::android::ApplicationStatusListener> + app_status_listener_; +#endif + + // True if running on android and the app is in the background. + bool app_on_background_ = false; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<CacheStorage> weak_factory_{this}; }; } // namespace content
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc similarity index 86% rename from content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc rename to content/browser/cache_storage/cache_storage_cache.cc index a84dbef..eb477c0 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +++ b/content/browser/cache_storage/cache_storage_cache.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 "content/browser/cache_storage/legacy/legacy_cache_storage_cache.h" +#include "content/browser/cache_storage/cache_storage_cache.h" #include <stddef.h> #include <algorithm> @@ -29,6 +29,7 @@ #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" +#include "content/browser/cache_storage/cache_storage.h" #include "content/browser/cache_storage/cache_storage.pb.h" #include "content/browser/cache_storage/cache_storage_blob_to_disk_cache.h" #include "content/browser/cache_storage/cache_storage_cache_entry_handler.h" @@ -39,7 +40,6 @@ #include "content/browser/cache_storage/cache_storage_quota_client.h" #include "content/browser/cache_storage/cache_storage_scheduler.h" #include "content/browser/cache_storage/cache_storage_trace_utils.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage.h" #include "content/common/background_fetch/background_fetch_types.h" #include "crypto/hmac.h" #include "crypto/symmetric_key.h" @@ -344,13 +344,13 @@ scoped_refptr<net::IOBufferWithSize> buffer = base::MakeRefCounted<net::IOBufferWithSize>( - entry->GetDataSize(LegacyCacheStorageCache::INDEX_HEADERS)); + entry->GetDataSize(CacheStorageCache::INDEX_HEADERS)); auto split_callback = base::SplitOnceCallback(base::BindOnce( ReadMetadataDidReadMetadata, entry, std::move(callback), buffer)); int read_rv = - entry->ReadData(LegacyCacheStorageCache::INDEX_HEADERS, 0, buffer.get(), + entry->ReadData(CacheStorageCache::INDEX_HEADERS, 0, buffer.get(), buffer->size(), std::move(split_callback.first)); if (read_rv != net::ERR_IO_PENDING) @@ -510,7 +510,7 @@ } // namespace -struct LegacyCacheStorageCache::QueryCacheResult { +struct CacheStorageCache::QueryCacheResult { QueryCacheResult(base::Time entry_time, int64_t padding, int64_t side_data_padding) @@ -526,7 +526,7 @@ int64_t side_data_padding = 0; }; -struct LegacyCacheStorageCache::QueryCacheContext { +struct CacheStorageCache::QueryCacheContext { QueryCacheContext(blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr options, QueryCacheCallback callback, @@ -556,7 +556,7 @@ std::unique_ptr<std::vector<QueryCacheResult>> matches; }; -struct LegacyCacheStorageCache::BatchInfo { +struct CacheStorageCache::BatchInfo { size_t remaining_operations = 0; VerboseErrorCallback callback; absl::optional<std::string> message; @@ -564,16 +564,15 @@ }; // static -std::unique_ptr<LegacyCacheStorageCache> -LegacyCacheStorageCache::CreateMemoryCache( +std::unique_ptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache( const blink::StorageKey& storage_key, storage::mojom::CacheStorageOwner owner, const std::string& cache_name, - LegacyCacheStorage* cache_storage, + CacheStorage* cache_storage, scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, scoped_refptr<BlobStorageContextWrapper> blob_storage_context) { - LegacyCacheStorageCache* cache = new LegacyCacheStorageCache( + CacheStorageCache* cache = new CacheStorageCache( storage_key, owner, cache_name, base::FilePath(), cache_storage, std::move(scheduler_task_runner), std::move(quota_manager_proxy), std::move(blob_storage_context), /*cache_size=*/0, @@ -584,19 +583,18 @@ } // static -std::unique_ptr<LegacyCacheStorageCache> -LegacyCacheStorageCache::CreatePersistentCache( +std::unique_ptr<CacheStorageCache> CacheStorageCache::CreatePersistentCache( const blink::StorageKey& storage_key, storage::mojom::CacheStorageOwner owner, const std::string& cache_name, - LegacyCacheStorage* cache_storage, + CacheStorage* cache_storage, const base::FilePath& path, scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, scoped_refptr<BlobStorageContextWrapper> blob_storage_context, int64_t cache_size, int64_t cache_padding) { - LegacyCacheStorageCache* cache = new LegacyCacheStorageCache( + CacheStorageCache* cache = new CacheStorageCache( storage_key, owner, cache_name, path, cache_storage, std::move(scheduler_task_runner), std::move(quota_manager_proxy), std::move(blob_storage_context), cache_size, cache_padding); @@ -605,15 +603,15 @@ return base::WrapUnique(cache); } -base::WeakPtr<LegacyCacheStorageCache> LegacyCacheStorageCache::AsWeakPtr() { +base::WeakPtr<CacheStorageCache> CacheStorageCache::AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } -CacheStorageCacheHandle LegacyCacheStorageCache::CreateHandle() { +CacheStorageCacheHandle CacheStorageCache::CreateHandle() { return CacheStorageCacheHandle(weak_ptr_factory_.GetWeakPtr()); } -void LegacyCacheStorageCache::AddHandleRef() { +void CacheStorageCache::AddHandleRef() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); handle_ref_count_ += 1; // Reference the parent CacheStorage while the Cache is referenced. Some @@ -623,7 +621,7 @@ cache_storage_handle_ = cache_storage_->CreateHandle(); } -void LegacyCacheStorageCache::DropHandleRef() { +void CacheStorageCache::DropHandleRef() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_GT(handle_ref_count_, 0U); handle_ref_count_ -= 1; @@ -636,17 +634,16 @@ } } -bool LegacyCacheStorageCache::IsUnreferenced() const { +bool CacheStorageCache::IsUnreferenced() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return !handle_ref_count_; } -void LegacyCacheStorageCache::Match( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - ResponseCallback callback) { +void CacheStorageCache::Match(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + ResponseCallback callback) { if (backend_state_ == BACKEND_CLOSED) { std::move(callback).Run( MakeErrorStorage(ErrorStorageType::kMatchBackendClosed), nullptr); @@ -658,12 +655,12 @@ id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch, priority, base::BindOnce( - &LegacyCacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(), std::move(request), std::move(match_options), trace_id, priority, scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::MatchAll( +void CacheStorageCache::MatchAll( blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr match_options, int64_t trace_id, @@ -681,19 +678,18 @@ CacheStorageSchedulerOp::kMatchAll, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::MatchAllImpl, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - std::move(match_options), trace_id, + &CacheStorageCache::MatchAllImpl, weak_ptr_factory_.GetWeakPtr(), + std::move(request), std::move(match_options), trace_id, CacheStorageSchedulerPriority::kNormal, scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::WriteSideData(ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len) { +void CacheStorageCache::WriteSideData(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len) { if (backend_state_ == BACKEND_CLOSED) { scheduler_task_runner_->PostTask( FROM_HERE, @@ -708,12 +704,12 @@ quota_manager_proxy_->GetUsageAndQuota( storage_key_, blink::mojom::StorageType::kTemporary, scheduler_task_runner_, - base::BindOnce(&LegacyCacheStorageCache::WriteSideDataDidGetQuota, + base::BindOnce(&CacheStorageCache::WriteSideDataDidGetQuota, weak_ptr_factory_.GetWeakPtr(), std::move(callback), url, expected_response_time, trace_id, buffer, buf_len)); } -void LegacyCacheStorageCache::BatchOperation( +void CacheStorageCache::BatchOperation( std::vector<blink::mojom::BatchOperationPtr> operations, int64_t trace_id, VerboseErrorCallback callback, @@ -796,7 +792,7 @@ quota_manager_proxy_->GetUsageAndQuota( storage_key_, blink::mojom::StorageType::kTemporary, scheduler_task_runner_, - base::BindOnce(&LegacyCacheStorageCache::BatchDidGetUsageAndQuota, + base::BindOnce(&CacheStorageCache::BatchDidGetUsageAndQuota, weak_ptr_factory_.GetWeakPtr(), std::move(operations), trace_id, std::move(callback), std::move(bad_message_callback), std::move(message), @@ -811,7 +807,7 @@ 0 /* quota */); } -void LegacyCacheStorageCache::BatchDidGetUsageAndQuota( +void CacheStorageCache::BatchDidGetUsageAndQuota( std::vector<blink::mojom::BatchOperationPtr> operations, int64_t trace_id, VerboseErrorCallback callback, @@ -823,7 +819,7 @@ int64_t usage, int64_t quota) { TRACE_EVENT_WITH_FLOW1("CacheStorage", - "LegacyCacheStorageCache::BatchDidGetUsageAndQuota", + "CacheStorageCache::BatchDidGetUsageAndQuota", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "operations", CacheStorageTracedValue(operations)); @@ -857,8 +853,7 @@ bool skip_side_data = safe_space_required_with_side_data.ValueOrDie() > quota; auto completion_callback = base::BindRepeating( - &LegacyCacheStorageCache::BatchDidOneOperation, - weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::BatchDidOneOperation, weak_ptr_factory_.GetWeakPtr(), base::OwnedRef(BatchInfo{operations.size(), std::move(callback), std::move(message), trace_id})); @@ -893,10 +888,10 @@ } } -void LegacyCacheStorageCache::BatchDidOneOperation(BatchInfo& batch_status, - CacheStorageError error) { +void CacheStorageCache::BatchDidOneOperation(BatchInfo& batch_status, + CacheStorageError error) { TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::BatchDidOneOperation", + "CacheStorageCache::BatchDidOneOperation", TRACE_ID_GLOBAL(batch_status.trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); // Nothing further to report after the callback is called. @@ -912,7 +907,7 @@ std::move(batch_status.message))); } else if (batch_status.remaining_operations == 0) { TRACE_EVENT_WITH_FLOW0( - "CacheStorage", "LegacyCacheStorageCache::BatchDidAllOperations", + "CacheStorage", "CacheStorageCache::BatchDidAllOperations", TRACE_ID_GLOBAL(batch_status.trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); std::move(batch_status.callback) @@ -921,10 +916,10 @@ } } -void LegacyCacheStorageCache::Keys(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - RequestsCallback callback) { +void CacheStorageCache::Keys(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback) { if (backend_state_ == BACKEND_CLOSED) { std::move(callback).Run( MakeErrorStorage(ErrorStorageType::kKeysBackendClosed), nullptr); @@ -936,25 +931,25 @@ id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::KeysImpl, weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::KeysImpl, weak_ptr_factory_.GetWeakPtr(), std::move(request), std::move(options), trace_id, scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::Close(base::OnceClosure callback) { +void CacheStorageCache::Close(base::OnceClosure callback) { DCHECK_NE(BACKEND_CLOSED, backend_state_) - << "Was LegacyCacheStorageCache::Close() called twice?"; + << "Was CacheStorageCache::Close() called twice?"; auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kClose, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::CloseImpl, weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::CloseImpl, weak_ptr_factory_.GetWeakPtr(), scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::Size(SizeCallback callback) { +void CacheStorageCache::Size(SizeCallback callback) { if (backend_state_ == BACKEND_CLOSED) { // TODO(jkarlin): Delete caches that can't be initialized. scheduler_task_runner_->PostTask(FROM_HERE, @@ -967,11 +962,11 @@ id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(), scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::GetSizeThenClose(SizeCallback callback) { +void CacheStorageCache::GetSizeThenClose(SizeCallback callback) { if (backend_state_ == BACKEND_CLOSED) { scheduler_task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(callback), 0)); @@ -984,20 +979,20 @@ CacheStorageSchedulerOp::kSizeThenClose, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(), base::BindOnce( - &LegacyCacheStorageCache::GetSizeThenCloseDidGetSize, + &CacheStorageCache::GetSizeThenCloseDidGetSize, weak_ptr_factory_.GetWeakPtr(), scheduler_->WrapCallbackToRunNext(id, std::move(callback))))); } -void LegacyCacheStorageCache::SetObserver(CacheStorageCacheObserver* observer) { +void CacheStorageCache::SetObserver(CacheStorageCacheObserver* observer) { DCHECK((observer == nullptr) ^ (cache_observer_ == nullptr)); cache_observer_ = observer; } // static -size_t LegacyCacheStorageCache::EstimatedStructSize( +size_t CacheStorageCache::EstimatedStructSize( const blink::mojom::FetchAPIRequestPtr& request) { size_t size = sizeof(*request); size += request->url.spec().size(); @@ -1010,20 +1005,20 @@ return size; } -LegacyCacheStorageCache::~LegacyCacheStorageCache() = default; +CacheStorageCache::~CacheStorageCache() = default; -void LegacyCacheStorageCache::SetSchedulerForTesting( +void CacheStorageCache::SetSchedulerForTesting( std::unique_ptr<CacheStorageScheduler> scheduler) { DCHECK(!scheduler_->ScheduledOperations()); scheduler_ = std::move(scheduler); } -LegacyCacheStorageCache::LegacyCacheStorageCache( +CacheStorageCache::CacheStorageCache( const blink::StorageKey& storage_key, storage::mojom::CacheStorageOwner owner, const std::string& cache_name, const base::FilePath& path, - LegacyCacheStorage* cache_storage, + CacheStorage* cache_storage, scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, scoped_refptr<BlobStorageContextWrapper> blob_storage_context, @@ -1057,12 +1052,11 @@ } } -void LegacyCacheStorageCache::QueryCache( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - QueryTypes query_types, - CacheStorageSchedulerPriority priority, - QueryCacheCallback callback) { +void CacheStorageCache::QueryCache(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + QueryTypes query_types, + CacheStorageSchedulerPriority priority, + QueryCacheCallback callback) { DCHECK_NE( QUERY_CACHE_ENTRIES | QUERY_CACHE_RESPONSES_WITH_BODIES, query_types & (QUERY_CACHE_ENTRIES | QUERY_CACHE_RESPONSES_WITH_BODIES)); @@ -1096,7 +1090,7 @@ // URL. auto split_callback = base::SplitOnceCallback(base::BindOnce( - &LegacyCacheStorageCache::QueryCacheDidOpenFastPath, + &CacheStorageCache::QueryCacheDidOpenFastPath, weak_ptr_factory_.GetWeakPtr(), std::move(query_cache_context))); disk_cache::EntryResult result = @@ -1111,7 +1105,7 @@ QueryCacheOpenNextEntry(std::move(query_cache_context)); } -void LegacyCacheStorageCache::QueryCacheDidOpenFastPath( +void CacheStorageCache::QueryCacheDidOpenFastPath( std::unique_ptr<QueryCacheContext> query_cache_context, disk_cache::EntryResult result) { if (result.net_error() != net::OK) { @@ -1124,12 +1118,12 @@ QueryCacheFilterEntry(std::move(query_cache_context), std::move(result)); } -void LegacyCacheStorageCache::QueryCacheOpenNextEntry( +void CacheStorageCache::QueryCacheOpenNextEntry( std::unique_ptr<QueryCacheContext> query_cache_context) { query_cache_recursive_depth_ += 1; auto cleanup = base::ScopedClosureRunner(base::BindOnce( [](CacheStorageCacheHandle handle) { - LegacyCacheStorageCache* self = From(handle); + CacheStorageCache* self = From(handle); if (!self) return; DCHECK_GT(self->query_cache_recursive_depth_, 0); @@ -1152,8 +1146,8 @@ *query_cache_context->backend_iterator; auto split_callback = base::SplitOnceCallback(base::BindOnce( - &LegacyCacheStorageCache::QueryCacheFilterEntry, - weak_ptr_factory_.GetWeakPtr(), std::move(query_cache_context))); + &CacheStorageCache::QueryCacheFilterEntry, weak_ptr_factory_.GetWeakPtr(), + std::move(query_cache_context))); disk_cache::EntryResult result = iterator.OpenNextEntry(std::move(split_callback.first)); @@ -1175,7 +1169,7 @@ base::BindOnce(std::move(split_callback.second), std::move(result))); } -void LegacyCacheStorageCache::QueryCacheFilterEntry( +void CacheStorageCache::QueryCacheFilterEntry( std::unique_ptr<QueryCacheContext> query_cache_context, disk_cache::EntryResult result) { if (result.net_error() == net::ERR_FAILED) { @@ -1221,12 +1215,12 @@ disk_cache::Entry* entry_ptr = entry.get(); ReadMetadata( entry_ptr, - base::BindOnce(&LegacyCacheStorageCache::QueryCacheDidReadMetadata, + base::BindOnce(&CacheStorageCache::QueryCacheDidReadMetadata, weak_ptr_factory_.GetWeakPtr(), std::move(query_cache_context), std::move(entry))); } -void LegacyCacheStorageCache::QueryCacheDidReadMetadata( +void CacheStorageCache::QueryCacheDidReadMetadata( std::unique_ptr<QueryCacheContext> query_cache_context, disk_cache::ScopedEntryPtr entry, std::unique_ptr<proto::CacheMetadata> metadata) { @@ -1332,7 +1326,7 @@ QueryCacheOpenNextEntry(std::move(query_cache_context)); } -void LegacyCacheStorageCache::QueryCacheUpgradePadding( +void CacheStorageCache::QueryCacheUpgradePadding( std::unique_ptr<QueryCacheContext> query_cache_context, disk_cache::ScopedEntryPtr entry, std::unique_ptr<proto::CacheMetadata> metadata) { @@ -1356,7 +1350,7 @@ WriteMetadata( temp_entry_ptr, *temp_metadata_ptr, base::BindOnce( - [](base::WeakPtr<LegacyCacheStorageCache> self, + [](base::WeakPtr<CacheStorageCache> self, std::unique_ptr<QueryCacheContext> query_cache_context, disk_cache::ScopedEntryPtr entry, std::unique_ptr<proto::CacheMetadata> metadata, int expected_bytes, @@ -1380,14 +1374,13 @@ } // static -bool LegacyCacheStorageCache::QueryCacheResultCompare( - const QueryCacheResult& lhs, - const QueryCacheResult& rhs) { +bool CacheStorageCache::QueryCacheResultCompare(const QueryCacheResult& lhs, + const QueryCacheResult& rhs) { return lhs.entry_time < rhs.entry_time; } // static -size_t LegacyCacheStorageCache::EstimatedResponseSizeWithoutBlob( +size_t CacheStorageCache::EstimatedResponseSizeWithoutBlob( const blink::mojom::FetchAPIResponse& response) { size_t size = sizeof(blink::mojom::FetchAPIResponse); for (const auto& url : response.url_list) @@ -1405,11 +1398,11 @@ } // static -int32_t LegacyCacheStorageCache::GetResponsePaddingVersion() { +int32_t CacheStorageCache::GetResponsePaddingVersion() { return kCachePaddingAlgorithmVersion; } -void LegacyCacheStorageCache::MatchImpl( +void CacheStorageCache::MatchImpl( blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr match_options, int64_t trace_id, @@ -1417,11 +1410,11 @@ ResponseCallback callback) { MatchAllImpl( std::move(request), std::move(match_options), trace_id, priority, - base::BindOnce(&LegacyCacheStorageCache::MatchDidMatchAll, + base::BindOnce(&CacheStorageCache::MatchDidMatchAll, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void LegacyCacheStorageCache::MatchDidMatchAll( +void CacheStorageCache::MatchDidMatchAll( ResponseCallback callback, CacheStorageError match_all_error, std::vector<blink::mojom::FetchAPIResponsePtr> match_all_responses) { @@ -1439,15 +1432,13 @@ std::move(match_all_responses[0])); } -void LegacyCacheStorageCache::MatchAllImpl( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - CacheStorageSchedulerPriority priority, - ResponsesCallback callback) { +void CacheStorageCache::MatchAllImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + CacheStorageSchedulerPriority priority, + ResponsesCallback callback) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); - TRACE_EVENT_WITH_FLOW2("CacheStorage", - "LegacyCacheStorageCache::MatchAllImpl", + TRACE_EVENT_WITH_FLOW2("CacheStorage", "CacheStorageCache::MatchAllImpl", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "request", CacheStorageTracedValue(request), "options", @@ -1465,18 +1456,18 @@ QueryCache(std::move(request), std::move(options), QUERY_CACHE_REQUESTS | QUERY_CACHE_RESPONSES_WITH_BODIES, priority, - base::BindOnce(&LegacyCacheStorageCache::MatchAllDidQueryCache, + base::BindOnce(&CacheStorageCache::MatchAllDidQueryCache, weak_ptr_factory_.GetWeakPtr(), std::move(callback), trace_id)); } -void LegacyCacheStorageCache::MatchAllDidQueryCache( +void CacheStorageCache::MatchAllDidQueryCache( ResponsesCallback callback, int64_t trace_id, CacheStorageError error, std::unique_ptr<QueryCacheResults> query_cache_results) { TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::MatchAllDidQueryCache", + "CacheStorageCache::MatchAllDidQueryCache", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -1497,10 +1488,9 @@ std::move(out_responses)); } -void LegacyCacheStorageCache::WriteMetadata( - disk_cache::Entry* entry, - const proto::CacheMetadata& metadata, - WriteMetadataCallback callback) { +void CacheStorageCache::WriteMetadata(disk_cache::Entry* entry, + const proto::CacheMetadata& metadata, + WriteMetadataCallback callback) { std::unique_ptr<std::string> serialized = std::make_unique<std::string>(); if (!metadata.SerializeToString(serialized.get())) { std::move(callback).Run(0, -1); @@ -1528,7 +1518,7 @@ std::move(split_callback.second).Run(rv); } -void LegacyCacheStorageCache::WriteSideDataDidGetQuota( +void CacheStorageCache::WriteSideDataDidGetQuota( ErrorCallback callback, const GURL& url, base::Time expected_response_time, @@ -1539,7 +1529,7 @@ int64_t usage, int64_t quota) { TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::WriteSideDataDidGetQuota", + "CacheStorageCache::WriteSideDataDidGetQuota", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -1556,24 +1546,23 @@ id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kWriteSideData, CacheStorageSchedulerPriority::kNormal, - base::BindOnce(&LegacyCacheStorageCache::WriteSideDataImpl, + base::BindOnce(&CacheStorageCache::WriteSideDataImpl, weak_ptr_factory_.GetWeakPtr(), scheduler_->WrapCallbackToRunNext(id, std::move(callback)), url, expected_response_time, trace_id, buffer, buf_len)); } -void LegacyCacheStorageCache::WriteSideDataImpl( - ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len) { +void CacheStorageCache::WriteSideDataImpl(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); - TRACE_EVENT_WITH_FLOW1( - "CacheStorage", "LegacyCacheStorageCache::WriteSideDataImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "url", url.spec()); + TRACE_EVENT_WITH_FLOW1("CacheStorage", "CacheStorageCache::WriteSideDataImpl", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "url", url.spec()); if (backend_state_ != BACKEND_OPEN) { std::move(callback).Run( MakeErrorStorage(ErrorStorageType::kWriteSideDataImplBackendClosed)); @@ -1585,7 +1574,7 @@ callback = WrapCallbackWithHandle(std::move(callback)); auto split_callback = base::SplitOnceCallback( - base::BindOnce(&LegacyCacheStorageCache::WriteSideDataDidOpenEntry, + base::BindOnce(&CacheStorageCache::WriteSideDataDidOpenEntry, weak_ptr_factory_.GetWeakPtr(), std::move(callback), expected_response_time, trace_id, buffer, buf_len)); @@ -1598,7 +1587,7 @@ std::move(split_callback.second).Run(std::move(result)); } -void LegacyCacheStorageCache::WriteSideDataDidOpenEntry( +void CacheStorageCache::WriteSideDataDidOpenEntry( ErrorCallback callback, base::Time expected_response_time, int64_t trace_id, @@ -1606,7 +1595,7 @@ int buf_len, disk_cache::EntryResult result) { TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::WriteSideDataDidOpenEntry", + "CacheStorageCache::WriteSideDataDidOpenEntry", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -1621,15 +1610,14 @@ ScopedWritableEntry entry(result.ReleaseEntry()); disk_cache::Entry* entry_ptr = entry.get(); - ReadMetadata( - entry_ptr, - base::BindOnce(&LegacyCacheStorageCache::WriteSideDataDidReadMetaData, - weak_ptr_factory_.GetWeakPtr(), std::move(callback), - expected_response_time, trace_id, buffer, buf_len, - std::move(entry))); + ReadMetadata(entry_ptr, + base::BindOnce(&CacheStorageCache::WriteSideDataDidReadMetaData, + weak_ptr_factory_.GetWeakPtr(), + std::move(callback), expected_response_time, + trace_id, buffer, buf_len, std::move(entry))); } -void LegacyCacheStorageCache::WriteSideDataDidReadMetaData( +void CacheStorageCache::WriteSideDataDidReadMetaData( ErrorCallback callback, base::Time expected_response_time, int64_t trace_id, @@ -1637,10 +1625,10 @@ int buf_len, ScopedWritableEntry entry, std::unique_ptr<proto::CacheMetadata> headers) { - TRACE_EVENT_WITH_FLOW0( - "CacheStorage", "LegacyCacheStorageCache::WriteSideDataDidReadMetaData", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + TRACE_EVENT_WITH_FLOW0("CacheStorage", + "CacheStorageCache::WriteSideDataDidReadMetaData", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); if (!headers || headers->response().response_time() != expected_response_time.ToInternalValue()) { WriteSideDataComplete(std::move(callback), std::move(entry), @@ -1655,7 +1643,7 @@ // BindRepeating() cannot be used directly because |callback|, |entry| and // |response| are not copyable. auto split_callback = base::SplitOnceCallback( - base::BindOnce(&LegacyCacheStorageCache::WriteSideDataDidWrite, + base::BindOnce(&CacheStorageCache::WriteSideDataDidWrite, weak_ptr_factory_.GetWeakPtr(), std::move(callback), std::move(entry), buf_len, std::move(headers), trace_id)); @@ -1668,7 +1656,7 @@ std::move(split_callback.second).Run(rv); } -void LegacyCacheStorageCache::WriteSideDataDidWrite( +void CacheStorageCache::WriteSideDataDidWrite( ErrorCallback callback, ScopedWritableEntry entry, int expected_bytes, @@ -1676,7 +1664,7 @@ int64_t trace_id, int rv) { TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::WriteSideDataDidWrite", + "CacheStorageCache::WriteSideDataDidWrite", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN); if (rv != expected_bytes) { WriteSideDataComplete(std::move(callback), std::move(entry), @@ -1700,7 +1688,7 @@ WriteMetadata( temp_entry_ptr, *metadata, - base::BindOnce(&LegacyCacheStorageCache::WriteSideDataDidWriteMetadata, + base::BindOnce(&CacheStorageCache::WriteSideDataDidWriteMetadata, weak_ptr_factory_.GetWeakPtr(), std::move(callback), std::move(entry), response->padding(), response->side_data_padding())); @@ -1712,13 +1700,12 @@ CacheStorageError::kSuccess); } -void LegacyCacheStorageCache::WriteSideDataDidWriteMetadata( - ErrorCallback callback, - ScopedWritableEntry entry, - int64_t padding, - int64_t side_data_padding, - int expected_bytes, - int rv) { +void CacheStorageCache::WriteSideDataDidWriteMetadata(ErrorCallback callback, + ScopedWritableEntry entry, + int64_t padding, + int64_t side_data_padding, + int expected_bytes, + int rv) { auto result = blink::mojom::CacheStorageError::kSuccess; if (rv != expected_bytes) { result = MakeErrorStorage( @@ -1728,7 +1715,7 @@ side_data_padding, result); } -void LegacyCacheStorageCache::WriteSideDataComplete( +void CacheStorageCache::WriteSideDataComplete( ErrorCallback callback, ScopedWritableEntry entry, int64_t padding, @@ -1755,19 +1742,19 @@ UpdateCacheSize(base::BindOnce(std::move(callback), error)); } -void LegacyCacheStorageCache::Put(blink::mojom::BatchOperationPtr operation, - int64_t trace_id, - ErrorCallback callback) { +void CacheStorageCache::Put(blink::mojom::BatchOperationPtr operation, + int64_t trace_id, + ErrorCallback callback) { DCHECK(BACKEND_OPEN == backend_state_ || initializing_); DCHECK_EQ(blink::mojom::OperationType::kPut, operation->operation_type); Put(std::move(operation->request), std::move(operation->response), trace_id, std::move(callback)); } -void LegacyCacheStorageCache::Put(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - ErrorCallback callback) { +void CacheStorageCache::Put(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) { DCHECK(BACKEND_OPEN == backend_state_ || initializing_); UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.Cache.AllWritesResponseType", @@ -1782,14 +1769,14 @@ scheduler_->ScheduleOperation( id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kPut, CacheStorageSchedulerPriority::kNormal, - base::BindOnce(&LegacyCacheStorageCache::PutImpl, + base::BindOnce(&CacheStorageCache::PutImpl, weak_ptr_factory_.GetWeakPtr(), std::move(put_context))); } -void LegacyCacheStorageCache::PutImpl(std::unique_ptr<PutContext> put_context) { +void CacheStorageCache::PutImpl(std::unique_ptr<PutContext> put_context) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); TRACE_EVENT_WITH_FLOW2( - "CacheStorage", "LegacyCacheStorageCache::PutImpl", + "CacheStorage", "CacheStorageCache::PutImpl", TRACE_ID_GLOBAL(put_context->trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "request", CacheStorageTracedValue(put_context->request), "response", @@ -1823,15 +1810,14 @@ query_options->ignore_vary = true; DeleteImpl( std::move(delete_request), std::move(query_options), - base::BindOnce(&LegacyCacheStorageCache::PutDidDeleteEntry, + base::BindOnce(&CacheStorageCache::PutDidDeleteEntry, weak_ptr_factory_.GetWeakPtr(), std::move(put_context))); } -void LegacyCacheStorageCache::PutDidDeleteEntry( +void CacheStorageCache::PutDidDeleteEntry( std::unique_ptr<PutContext> put_context, CacheStorageError error) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::PutDidDeleteEntry", + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorageCache::PutDidDeleteEntry", TRACE_ID_GLOBAL(put_context->trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); if (backend_state_ != BACKEND_OPEN) { @@ -1851,7 +1837,7 @@ disk_cache::Backend* backend_ptr = backend_.get(); auto split_callback = base::SplitOnceCallback( - base::BindOnce(&LegacyCacheStorageCache::PutDidCreateEntry, + base::BindOnce(&CacheStorageCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(), std::move(put_context))); DCHECK(scheduler_->IsRunningExclusiveOperation()); @@ -1862,11 +1848,10 @@ std::move(split_callback.second).Run(std::move(result)); } -void LegacyCacheStorageCache::PutDidCreateEntry( +void CacheStorageCache::PutDidCreateEntry( std::unique_ptr<PutContext> put_context, disk_cache::EntryResult result) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::PutDidCreateEntry", + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorageCache::PutDidCreateEntry", TRACE_ID_GLOBAL(put_context->trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -1954,20 +1939,20 @@ WriteMetadata( temp_entry_ptr, metadata, - base::BindOnce(&LegacyCacheStorageCache::PutDidWriteHeaders, + base::BindOnce(&CacheStorageCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(), std::move(put_context), response_metadata->padding(), response_metadata->side_data_padding())); } -void LegacyCacheStorageCache::PutDidWriteHeaders( +void CacheStorageCache::PutDidWriteHeaders( std::unique_ptr<PutContext> put_context, int64_t padding, int64_t side_data_padding, int expected_bytes, int rv) { TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::PutDidWriteHeaders", + "CacheStorageCache::PutDidWriteHeaders", TRACE_ID_GLOBAL(put_context->trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -1986,14 +1971,14 @@ PutWriteBlobToCache(std::move(put_context), INDEX_RESPONSE_BODY); } -void LegacyCacheStorageCache::PutWriteBlobToCache( +void CacheStorageCache::PutWriteBlobToCache( std::unique_ptr<PutContext> put_context, int disk_cache_body_index) { DCHECK(disk_cache_body_index == INDEX_RESPONSE_BODY || disk_cache_body_index == INDEX_SIDE_DATA); TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::PutWriteBlobToCache", + "CacheStorageCache::PutWriteBlobToCache", TRACE_ID_GLOBAL(put_context->trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -2026,7 +2011,7 @@ disk_cache::Entry* temp_entry_ptr = entry.get(); auto clear_callback = - base::BindOnce(&LegacyCacheStorageCache::PutWriteBlobToCacheComplete, + base::BindOnce(&CacheStorageCache::PutWriteBlobToCacheComplete, weak_ptr_factory_.GetWeakPtr(), std::move(put_context), disk_cache_body_index, std::move(entry)); @@ -2061,12 +2046,12 @@ blob_to_cache_raw->StreamBlobToCache( std::move(entry), disk_cache_body_index, std::move(blob), blob_size, - base::BindOnce(&LegacyCacheStorageCache::PutDidWriteBlobToCache, + base::BindOnce(&CacheStorageCache::PutDidWriteBlobToCache, weak_ptr_factory_.GetWeakPtr(), std::move(put_context), blob_to_cache_key, disk_cache_body_index)); } -void LegacyCacheStorageCache::PutDidWriteBlobToCache( +void CacheStorageCache::PutDidWriteBlobToCache( std::unique_ptr<PutContext> put_context, BlobToDiskCacheIDMap::KeyType blob_to_cache_key, int disk_cache_body_index, @@ -2074,7 +2059,7 @@ bool success) { DCHECK(entry); TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::PutDidWriteBlobToCache", + "CacheStorageCache::PutDidWriteBlobToCache", TRACE_ID_GLOBAL(put_context->trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -2085,7 +2070,7 @@ (success ? net::OK : net::ERR_FAILED)); } -void LegacyCacheStorageCache::PutWriteBlobToCacheComplete( +void CacheStorageCache::PutWriteBlobToCacheComplete( std::unique_ptr<PutContext> put_context, int disk_cache_body_index, ScopedWritableEntry entry, @@ -2109,9 +2094,8 @@ PutComplete(std::move(put_context), CacheStorageError::kSuccess); } -void LegacyCacheStorageCache::PutComplete( - std::unique_ptr<PutContext> put_context, - blink::mojom::CacheStorageError error) { +void CacheStorageCache::PutComplete(std::unique_ptr<PutContext> put_context, + blink::mojom::CacheStorageError error) { if (error == CacheStorageError::kSuccess) { // Make sure we've written everything. DCHECK(put_context->cache_entry); @@ -2126,10 +2110,10 @@ UpdateCacheSize(base::BindOnce(std::move(put_context->callback), error)); } -void LegacyCacheStorageCache::CalculateCacheSizePadding( +void CacheStorageCache::CalculateCacheSizePadding( SizePaddingCallback got_sizes_callback) { auto split_callback = base::SplitOnceCallback(base::BindOnce( - &LegacyCacheStorageCache::CalculateCacheSizePaddingGotSize, + &CacheStorageCache::CalculateCacheSizePaddingGotSize, weak_ptr_factory_.GetWeakPtr(), std::move(got_sizes_callback))); int64_t rv = @@ -2138,7 +2122,7 @@ std::move(split_callback.second).Run(rv); } -void LegacyCacheStorageCache::CalculateCacheSizePaddingGotSize( +void CacheStorageCache::CalculateCacheSizePaddingGotSize( SizePaddingCallback callback, int64_t cache_size) { // Enumerating entries is only done during cache initialization and only if @@ -2151,12 +2135,12 @@ QueryCache(std::move(request), std::move(options), QUERY_CACHE_RESPONSES_NO_BODIES, CacheStorageSchedulerPriority::kNormal, - base::BindOnce(&LegacyCacheStorageCache::PaddingDidQueryCache, + base::BindOnce(&CacheStorageCache::PaddingDidQueryCache, weak_ptr_factory_.GetWeakPtr(), std::move(callback), cache_size)); } -void LegacyCacheStorageCache::PaddingDidQueryCache( +void CacheStorageCache::PaddingDidQueryCache( SizePaddingCallback callback, int64_t cache_size, CacheStorageError error, @@ -2173,7 +2157,7 @@ std::move(callback).Run(cache_size, cache_padding); } -void LegacyCacheStorageCache::CalculateCacheSize( +void CacheStorageCache::CalculateCacheSize( net::Int64CompletionOnceCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto split_callback = base::SplitOnceCallback(std::move(callback)); @@ -2183,7 +2167,7 @@ std::move(split_callback.second).Run(rv); } -void LegacyCacheStorageCache::UpdateCacheSize(base::OnceClosure callback) { +void CacheStorageCache::UpdateCacheSize(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (backend_state_ != BACKEND_OPEN) return; @@ -2191,12 +2175,12 @@ // Note that the callback holds a cache handle to keep the cache alive during // the operation since this UpdateCacheSize is often run after an operation // completes and runs its callback. - CalculateCacheSize(base::BindOnce( - &LegacyCacheStorageCache::UpdateCacheSizeGotSize, - weak_ptr_factory_.GetWeakPtr(), CreateHandle(), std::move(callback))); + CalculateCacheSize(base::BindOnce(&CacheStorageCache::UpdateCacheSizeGotSize, + weak_ptr_factory_.GetWeakPtr(), + CreateHandle(), std::move(callback))); } -void LegacyCacheStorageCache::UpdateCacheSizeGotSize( +void CacheStorageCache::UpdateCacheSizeGotSize( CacheStorageCacheHandle cache_handle, base::OnceClosure callback, int64_t current_cache_size) { @@ -2210,12 +2194,11 @@ CacheStorageQuotaClient::GetClientTypeFromOwner(owner_), storage_key_, blink::mojom::StorageType::kTemporary, size_delta, base::Time::Now(), scheduler_task_runner_, - base::BindOnce( - &LegacyCacheStorageCache::UpdateCacheSizeNotifiedStorageModified, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + base::BindOnce(&CacheStorageCache::UpdateCacheSizeNotifiedStorageModified, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void LegacyCacheStorageCache::UpdateCacheSizeNotifiedStorageModified( +void CacheStorageCache::UpdateCacheSizeNotifiedStorageModified( base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (cache_storage_) @@ -2227,7 +2210,7 @@ std::move(callback).Run(); } -void LegacyCacheStorageCache::GetAllMatchedEntries( +void CacheStorageCache::GetAllMatchedEntries( blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr options, int64_t trace_id, @@ -2244,20 +2227,20 @@ CacheStorageSchedulerOp::kGetAllMatched, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::GetAllMatchedEntriesImpl, + &CacheStorageCache::GetAllMatchedEntriesImpl, weak_ptr_factory_.GetWeakPtr(), std::move(request), std::move(options), trace_id, scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::GetAllMatchedEntriesImpl( +void CacheStorageCache::GetAllMatchedEntriesImpl( blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr options, int64_t trace_id, CacheEntriesCallback callback) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); TRACE_EVENT_WITH_FLOW2("CacheStorage", - "LegacyCacheStorageCache::GetAllMatchedEntriesImpl", + "CacheStorageCache::GetAllMatchedEntriesImpl", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "request", CacheStorageTracedValue(request), "options", @@ -2278,21 +2261,20 @@ std::move(request), std::move(options), QUERY_CACHE_REQUESTS | QUERY_CACHE_RESPONSES_WITH_BODIES, CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorageCache::GetAllMatchedEntriesDidQueryCache, - weak_ptr_factory_.GetWeakPtr(), trace_id, std::move(callback))); + base::BindOnce(&CacheStorageCache::GetAllMatchedEntriesDidQueryCache, + weak_ptr_factory_.GetWeakPtr(), trace_id, + std::move(callback))); } -void LegacyCacheStorageCache::GetAllMatchedEntriesDidQueryCache( +void CacheStorageCache::GetAllMatchedEntriesDidQueryCache( int64_t trace_id, CacheEntriesCallback callback, blink::mojom::CacheStorageError error, std::unique_ptr<QueryCacheResults> query_cache_results) { - TRACE_EVENT_WITH_FLOW0( - "CacheStorage", - "LegacyCacheStorageCache::GetAllMatchedEntriesDidQueryCache", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + TRACE_EVENT_WITH_FLOW0("CacheStorage", + "CacheStorageCache::GetAllMatchedEntriesDidQueryCache", + TRACE_ID_GLOBAL(trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); if (error != CacheStorageError::kSuccess) { std::move(callback).Run(error, {}); @@ -2312,13 +2294,13 @@ std::move(callback).Run(CacheStorageError::kSuccess, std::move(entries)); } -CacheStorageCache::InitState LegacyCacheStorageCache::GetInitState() const { +CacheStorageCache::InitState CacheStorageCache::GetInitState() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return initializing_ ? InitState::Initializing : InitState::Initialized; } -void LegacyCacheStorageCache::Delete(blink::mojom::BatchOperationPtr operation, - ErrorCallback callback) { +void CacheStorageCache::Delete(blink::mojom::BatchOperationPtr operation, + ErrorCallback callback) { DCHECK(BACKEND_OPEN == backend_state_ || initializing_); DCHECK_EQ(blink::mojom::OperationType::kDelete, operation->operation_type); @@ -2334,12 +2316,12 @@ id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kDelete, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(), std::move(request), std::move(operation->match_options), scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } -void LegacyCacheStorageCache::DeleteImpl( +void CacheStorageCache::DeleteImpl( blink::mojom::FetchAPIRequestPtr request, blink::mojom::CacheQueryOptionsPtr match_options, ErrorCallback callback) { @@ -2358,11 +2340,11 @@ std::move(request), std::move(match_options), QUERY_CACHE_ENTRIES | QUERY_CACHE_RESPONSES_NO_BODIES, CacheStorageSchedulerPriority::kNormal, - base::BindOnce(&LegacyCacheStorageCache::DeleteDidQueryCache, + base::BindOnce(&CacheStorageCache::DeleteDidQueryCache, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void LegacyCacheStorageCache::DeleteDidQueryCache( +void CacheStorageCache::DeleteDidQueryCache( ErrorCallback callback, CacheStorageError error, std::unique_ptr<QueryCacheResults> query_cache_results) { @@ -2392,13 +2374,12 @@ base::BindOnce(std::move(callback), CacheStorageError::kSuccess)); } -void LegacyCacheStorageCache::KeysImpl( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - RequestsCallback callback) { +void CacheStorageCache::KeysImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); - TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorageCache::KeysImpl", + TRACE_EVENT_WITH_FLOW2("CacheStorage", "CacheStorageCache::KeysImpl", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "request", CacheStorageTracedValue(request), "options", @@ -2416,18 +2397,17 @@ QueryCache(std::move(request), std::move(options), QUERY_CACHE_REQUESTS, CacheStorageSchedulerPriority::kNormal, - base::BindOnce(&LegacyCacheStorageCache::KeysDidQueryCache, + base::BindOnce(&CacheStorageCache::KeysDidQueryCache, weak_ptr_factory_.GetWeakPtr(), std::move(callback), trace_id)); } -void LegacyCacheStorageCache::KeysDidQueryCache( +void CacheStorageCache::KeysDidQueryCache( RequestsCallback callback, int64_t trace_id, CacheStorageError error, std::unique_ptr<QueryCacheResults> query_cache_results) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorageCache::KeysDidQueryCache", + TRACE_EVENT_WITH_FLOW0("CacheStorage", "CacheStorageCache::KeysDidQueryCache", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); @@ -2443,7 +2423,7 @@ std::move(callback).Run(CacheStorageError::kSuccess, std::move(out_requests)); } -void LegacyCacheStorageCache::CloseImpl(base::OnceClosure callback) { +void CacheStorageCache::CloseImpl(base::OnceClosure callback) { DCHECK_EQ(BACKEND_OPEN, backend_state_); DCHECK(scheduler_->IsRunningExclusiveOperation()); @@ -2451,7 +2431,7 @@ post_backend_closed_callback_ = std::move(callback); } -void LegacyCacheStorageCache::DeleteBackendCompletedIO() { +void CacheStorageCache::DeleteBackendCompletedIO() { if (!post_backend_closed_callback_.is_null()) { DCHECK_NE(BACKEND_CLOSED, backend_state_); backend_state_ = BACKEND_CLOSED; @@ -2459,7 +2439,7 @@ } } -void LegacyCacheStorageCache::SizeImpl(SizeCallback callback) { +void CacheStorageCache::SizeImpl(SizeCallback callback) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); // TODO(cmumford): Can CacheStorage::kSizeUnknown be returned instead of zero? @@ -2474,13 +2454,13 @@ base::BindOnce(std::move(callback), size)); } -void LegacyCacheStorageCache::GetSizeThenCloseDidGetSize(SizeCallback callback, - int64_t cache_size) { +void CacheStorageCache::GetSizeThenCloseDidGetSize(SizeCallback callback, + int64_t cache_size) { cache_entry_handler_->InvalidateDiskCacheBlobEntrys(); CloseImpl(base::BindOnce(std::move(callback), cache_size)); } -void LegacyCacheStorageCache::CreateBackend(ErrorCallback callback) { +void CacheStorageCache::CreateBackend(ErrorCallback callback) { DCHECK(!backend_); // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction. @@ -2497,7 +2477,7 @@ ScopedBackendPtr* backend = backend_ptr.get(); auto split_callback = base::SplitOnceCallback( - base::BindOnce(&LegacyCacheStorageCache::CreateBackendDidCreate, + base::BindOnce(&CacheStorageCache::CreateBackendDidCreate, weak_ptr_factory_.GetWeakPtr(), std::move(callback), std::move(backend_ptr))); @@ -2505,15 +2485,15 @@ int rv = disk_cache::CreateCacheBackend( cache_type, net::CACHE_BACKEND_SIMPLE, /*file_operations=*/nullptr, path_, max_bytes, disk_cache::ResetHandling::kNeverReset, nullptr, backend, - base::BindOnce(&LegacyCacheStorageCache::DeleteBackendCompletedIO, + base::BindOnce(&CacheStorageCache::DeleteBackendCompletedIO, weak_ptr_factory_.GetWeakPtr()), std::move(split_callback.first)); if (rv != net::ERR_IO_PENDING) std::move(split_callback.second).Run(rv); } -void LegacyCacheStorageCache::CreateBackendDidCreate( - LegacyCacheStorageCache::ErrorCallback callback, +void CacheStorageCache::CreateBackendDidCreate( + CacheStorageCache::ErrorCallback callback, std::unique_ptr<ScopedBackendPtr> backend_ptr, int rv) { if (rv != net::OK) { @@ -2526,7 +2506,7 @@ std::move(callback).Run(CacheStorageError::kSuccess); } -void LegacyCacheStorageCache::InitBackend() { +void CacheStorageCache::InitBackend() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(BACKEND_UNINITIALIZED, backend_state_); DCHECK(!initializing_); @@ -2538,15 +2518,14 @@ id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kInit, CacheStorageSchedulerPriority::kNormal, base::BindOnce( - &LegacyCacheStorageCache::CreateBackend, - weak_ptr_factory_.GetWeakPtr(), + &CacheStorageCache::CreateBackend, weak_ptr_factory_.GetWeakPtr(), base::BindOnce( - &LegacyCacheStorageCache::InitDidCreateBackend, + &CacheStorageCache::InitDidCreateBackend, weak_ptr_factory_.GetWeakPtr(), scheduler_->WrapCallbackToRunNext(id, base::BindOnce([] {}))))); } -void LegacyCacheStorageCache::InitDidCreateBackend( +void CacheStorageCache::InitDidCreateBackend( base::OnceClosure callback, CacheStorageError cache_create_error) { if (cache_create_error != CacheStorageError::kSuccess) { @@ -2555,19 +2534,17 @@ } auto split_callback = base::SplitOnceCallback(std::move(callback)); - int64_t rv = backend_->CalculateSizeOfAllEntries( - base::BindOnce(&LegacyCacheStorageCache::InitGotCacheSize, - weak_ptr_factory_.GetWeakPtr(), - std::move(split_callback.first), cache_create_error)); + int64_t rv = backend_->CalculateSizeOfAllEntries(base::BindOnce( + &CacheStorageCache::InitGotCacheSize, weak_ptr_factory_.GetWeakPtr(), + std::move(split_callback.first), cache_create_error)); if (rv != net::ERR_IO_PENDING) InitGotCacheSize(std::move(split_callback.second), cache_create_error, rv); } -void LegacyCacheStorageCache::InitGotCacheSize( - base::OnceClosure callback, - CacheStorageError cache_create_error, - int64_t cache_size) { +void CacheStorageCache::InitGotCacheSize(base::OnceClosure callback, + CacheStorageError cache_create_error, + int64_t cache_size) { if (cache_create_error != CacheStorageError::kSuccess) { InitGotCacheSizeAndPadding(std::move(callback), cache_create_error, 0, 0); return; @@ -2585,7 +2562,7 @@ // We assume that if the sizes match then then cached padding is still // correct. If not then we recalculate the padding. CalculateCacheSizePaddingGotSize( - base::BindOnce(&LegacyCacheStorageCache::InitGotCacheSizeAndPadding, + base::BindOnce(&CacheStorageCache::InitGotCacheSizeAndPadding, weak_ptr_factory_.GetWeakPtr(), std::move(callback), cache_create_error), cache_size); @@ -2595,7 +2572,7 @@ if (cache_padding_ == CacheStorage::kSizeUnknown || cache_padding_ < 0) { CalculateCacheSizePaddingGotSize( - base::BindOnce(&LegacyCacheStorageCache::InitGotCacheSizeAndPadding, + base::BindOnce(&CacheStorageCache::InitGotCacheSizeAndPadding, weak_ptr_factory_.GetWeakPtr(), std::move(callback), cache_create_error), cache_size); @@ -2608,7 +2585,7 @@ cache_size, cache_padding_); } -void LegacyCacheStorageCache::InitGotCacheSizeAndPadding( +void CacheStorageCache::InitGotCacheSizeAndPadding( base::OnceClosure callback, CacheStorageError cache_create_error, int64_t cache_size, @@ -2632,7 +2609,7 @@ std::move(callback).Run(); } -int64_t LegacyCacheStorageCache::PaddedCacheSize() const { +int64_t CacheStorageCache::PaddedCacheSize() const { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); if (cache_size_ == CacheStorage::kSizeUnknown || cache_padding_ == CacheStorage::kSizeUnknown) { @@ -2642,7 +2619,7 @@ } base::CheckedNumeric<uint64_t> -LegacyCacheStorageCache::CalculateRequiredSafeSpaceForPut( +CacheStorageCache::CalculateRequiredSafeSpaceForPut( const blink::mojom::BatchOperationPtr& operation) { DCHECK_EQ(blink::mojom::OperationType::kPut, operation->operation_type); base::CheckedNumeric<uint64_t> safe_space_required = 0; @@ -2655,7 +2632,7 @@ } base::CheckedNumeric<uint64_t> -LegacyCacheStorageCache::CalculateRequiredSafeSpaceForRequest( +CacheStorageCache::CalculateRequiredSafeSpaceForRequest( const blink::mojom::FetchAPIRequestPtr& request) { base::CheckedNumeric<uint64_t> safe_space_required = 0; safe_space_required += request->method.size(); @@ -2671,7 +2648,7 @@ } base::CheckedNumeric<uint64_t> -LegacyCacheStorageCache::CalculateRequiredSafeSpaceForResponse( +CacheStorageCache::CalculateRequiredSafeSpaceForResponse( const blink::mojom::FetchAPIResponsePtr& response) { base::CheckedNumeric<uint64_t> safe_space_required = 0; safe_space_required += (response->blob ? response->blob->size : 0);
diff --git a/content/browser/cache_storage/cache_storage_cache.h b/content/browser/cache_storage/cache_storage_cache.h index 2096da49..bd895ee 100644 --- a/content/browser/cache_storage/cache_storage_cache.h +++ b/content/browser/cache_storage/cache_storage_cache.h
@@ -8,17 +8,50 @@ #include <stdint.h> #include <memory> +#include <string> #include <vector> #include "base/callback.h" +#include "base/containers/id_map.h" +#include "base/files/file_path.h" +#include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "components/services/storage/public/mojom/cache_storage_control.mojom.h" +#include "content/browser/cache_storage/blob_storage_context_wrapper.h" #include "content/browser/cache_storage/cache_storage_cache_handle.h" +#include "content/browser/cache_storage/cache_storage_handle.h" #include "content/browser/cache_storage/cache_storage_scheduler_types.h" +#include "content/browser/cache_storage/scoped_writable_entry.h" #include "content/common/content_export.h" +#include "net/base/completion_once_callback.h" #include "net/base/io_buffer.h" +#include "net/disk_cache/disk_cache.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h" +#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" + +namespace storage { +class QuotaManagerProxy; +} // namespace storage namespace content { +class CacheStorageBlobToDiskCache; +class CacheStorageCacheEntryHandler; +class CacheStorageCacheObserver; +class CacheStorageScheduler; +class CacheStorage; +struct PutContext; + +namespace proto { +class CacheMetadata; +} // namespace proto + +namespace cache_storage_cache_unittest { +class TestCacheStorageCache; +class CacheStorageCacheTest; +} // namespace cache_storage_cache_unittest // Represents a ServiceWorker Cache as seen in: // @@ -50,6 +83,9 @@ base::OnceCallback<void(blink::mojom::CacheStorageError, std::unique_ptr<Requests>)>; + using SizeCallback = base::OnceCallback<void(int64_t)>; + using SizePaddingCallback = base::OnceCallback<void(int64_t, int64_t)>; + // The stream index for a cache Entry. This cannot be extended without changes // in the Entry implementation. INDEX_SIDE_DATA is used for storing any // additional data, such as response side blobs or request bodies. @@ -60,33 +96,41 @@ INDEX_SIDE_DATA }; - // Create a handle that will hold the CacheStorageCache alive. Client code - // should hold one of these handles while waiting for operation callbacks to - // be invoked. - // - // Note, its still possible for the CacheStorageCache to be deleted even if - // there are outstanding handle references. This can occur when the user - // triggers a storage wipe, for example. The handle value should be treated - // as a weak pointer. - virtual CacheStorageCacheHandle CreateHandle() = 0; - virtual void AddHandleRef() = 0; - virtual void DropHandleRef() = 0; - virtual bool IsUnreferenced() const = 0; + static std::unique_ptr<CacheStorageCache> CreateMemoryCache( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + const std::string& cache_name, + CacheStorage* cache_storage, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context); + static std::unique_ptr<CacheStorageCache> CreatePersistentCache( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + const std::string& cache_name, + CacheStorage* cache_storage, + const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + int64_t cache_size, + int64_t cache_padding); + static int32_t GetResponsePaddingVersion(); // Returns ERROR_TYPE_NOT_FOUND if not found. - virtual void Match(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - ResponseCallback callback) = 0; + void Match(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + CacheStorageSchedulerPriority priority, + int64_t trace_id, + ResponseCallback callback); // Returns blink::mojom::CacheStorageError::kSuccess and matched // responses in this cache. If there are no responses, returns // blink::mojom::CacheStorageError::kSuccess and an empty vector. - virtual void MatchAll(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - int64_t trace_id, - ResponsesCallback callback) = 0; + void MatchAll(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponsesCallback callback); // Writes the side data (ex: V8 code cache) for the specified cache entry. // If it doesn't exist, or the |expected_response_time| differs from the @@ -94,12 +138,12 @@ // Note: This "side data" is same meaning as "metadata" in HTTPCache. We use // "metadata" in cache_storage.proto for the pair of headers of a request and // a response. To avoid the confusion we use "side data" here. - virtual void WriteSideData(ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len) = 0; + void WriteSideData(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len); // Runs given batch operations. This corresponds to the Batch Cache Operations // algorithm in the spec. @@ -114,42 +158,480 @@ // // TODO(nhiroki): This function should run all operations atomically. // http://crbug.com/486637 - virtual void BatchOperation( + void BatchOperation(std::vector<blink::mojom::BatchOperationPtr> operations, + int64_t trace_id, + VerboseErrorCallback callback, + BadMessageCallback bad_message_callback); + void BatchDidGetUsageAndQuota( std::vector<blink::mojom::BatchOperationPtr> operations, int64_t trace_id, VerboseErrorCallback callback, - BadMessageCallback bad_message_callback) = 0; + BadMessageCallback bad_message_callback, + absl::optional<std::string> message, + uint64_t space_required, + uint64_t side_data_size, + blink::mojom::QuotaStatusCode status_code, + int64_t usage, + int64_t quota); // Returns blink::mojom::CacheStorageError::kSuccess and a vector of // requests if there are no errors. - virtual void Keys(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - RequestsCallback callback) = 0; + void Keys(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback); + + // Closes the backend. Future operations that require the backend + // will exit early. Close should only be called once per CacheStorageCache. + void Close(base::OnceClosure callback); + + // The size of the cache's contents. The callback reports the padded + // size. If you want the unpadded size you may call the cache_size() + // getter method on the cache object when the callback is invoked; the + // getter will have an up-to-date value at that point. + void Size(SizeCallback callback); + + // Gets the cache's size, closes the backend, and then runs |callback| with + // the cache's size. As per the comment for Size(), this also returns the + // padded size. + void GetSizeThenClose(SizeCallback callback); // Puts the request/response pair in the cache. This is a public member to // directly bypass the batch operations and write into the cache. This is used // by non-CacheAPI owners. The Cache Storage API uses batch operations defined // in the dispatcher. - virtual void Put(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - ErrorCallback callback) = 0; + void Put(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback); // Similar to MatchAll, but returns the associated requests as well. - virtual void GetAllMatchedEntries( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - int64_t trace_id, - CacheEntriesCallback callback) = 0; + void GetAllMatchedEntries(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheEntriesCallback callback); // Try to determine the initialization state of the cache. Unknown may be // returned for cross-sequence clients using the cross-sequence wrappers. enum class InitState { Unknown, Initializing, Initialized }; - virtual InitState GetInitState() const = 0; + InitState GetInitState() const; - protected: - virtual ~CacheStorageCache() = default; + CacheStorageCache(const CacheStorageCache&) = delete; + CacheStorageCache& operator=(const CacheStorageCache&) = delete; + + // Async operations in progress will cancel and not run their callbacks. + virtual ~CacheStorageCache(); + + base::FilePath path() const { return path_; } + + std::string cache_name() const { return cache_name_; } + + int64_t cache_size() const { return cache_size_; } + + int64_t cache_padding() const { return cache_padding_; } + + // Return the total cache size (actual size + padding). If either is unknown + // then CacheStorage::kSizeUnknown is returned. + int64_t PaddedCacheSize() const; + + // Set the one observer that will be notified of changes to this cache. + // Note: Either the observer must have a lifetime longer than this instance + // or call SetObserver(nullptr) to stop receiving notification of changes. + void SetObserver(CacheStorageCacheObserver* observer); + + static size_t EstimatedStructSize( + const blink::mojom::FetchAPIRequestPtr& request); + + base::WeakPtr<CacheStorageCache> AsWeakPtr(); + + // Create a handle that will hold the CacheStorageCache alive. Client code + // should hold one of these handles while waiting for operation callbacks to + // be invoked. + // + // Note, its still possible for the CacheStorageCache to be deleted even if + // there are outstanding handle references. This can occur when the user + // triggers a storage wipe, for example. The handle value should be treated + // as a weak pointer. + CacheStorageCacheHandle CreateHandle(); + void AddHandleRef(); + void DropHandleRef(); + bool IsUnreferenced() const; + + // the default scheduler with a customized scheduler for testing. + // The current scheduler must be idle. + void SetSchedulerForTesting(std::unique_ptr<CacheStorageScheduler> scheduler); + + static CacheStorageCache* From(const CacheStorageCacheHandle& handle) { + return static_cast<CacheStorageCache*>(handle.value()); + } + + private: + // QueryCache types: + enum QueryCacheFlags { + QUERY_CACHE_REQUESTS = 0x1, + QUERY_CACHE_RESPONSES_WITH_BODIES = 0x2, + QUERY_CACHE_RESPONSES_NO_BODIES = 0x4, + QUERY_CACHE_ENTRIES = 0x8, + }; + + // The backend progresses from uninitialized, to open, to closed, and cannot + // reverse direction. The open step may be skipped. + enum BackendState { + BACKEND_UNINITIALIZED, // No backend, create backend on first operation. + BACKEND_OPEN, // Backend can be used. + BACKEND_CLOSED // Backend cannot be used. All ops should fail. + }; + + friend class base::RefCounted<CacheStorageCache>; + friend class cache_storage_cache_unittest::TestCacheStorageCache; + friend class cache_storage_cache_unittest::CacheStorageCacheTest; + + struct QueryCacheContext; + struct QueryCacheResult; + struct BatchInfo; + + using QueryTypes = int32_t; + using QueryCacheResults = std::vector<QueryCacheResult>; + using QueryCacheCallback = + base::OnceCallback<void(blink::mojom::CacheStorageError, + std::unique_ptr<QueryCacheResults>)>; + using Entries = std::vector<disk_cache::Entry*>; + using ScopedBackendPtr = std::unique_ptr<disk_cache::Backend>; + using BlobToDiskCacheIDMap = + base::IDMap<std::unique_ptr<CacheStorageBlobToDiskCache>>; + + CacheStorageCache( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + const std::string& cache_name, + const base::FilePath& path, + CacheStorage* cache_storage, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context, + int64_t cache_size, + int64_t cache_padding); + + // Callback passed to operations. If |error| is a real error, invokes + // |error_callback|. Always invokes |completion_closure| to signal + // completion. + void BatchDidOneOperation(BatchInfo& batch_status, + blink::mojom::CacheStorageError error); + + // Runs |callback| with matching requests/response data. The data provided + // in the QueryCacheResults depends on the |query_type|. If |query_type| is + // CACHE_ENTRIES then only out_entries is valid. If |query_type| is REQUESTS + // then only out_requests is valid. If |query_type| is + // REQUESTS_AND_RESPONSES then only out_requests, out_responses, and + // out_blob_data_handles are valid. + void QueryCache(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + QueryTypes query_types, + CacheStorageSchedulerPriority priority, + QueryCacheCallback callback); + void QueryCacheDidOpenFastPath( + std::unique_ptr<QueryCacheContext> query_cache_context, + disk_cache::EntryResult result); + void QueryCacheOpenNextEntry( + std::unique_ptr<QueryCacheContext> query_cache_context); + void QueryCacheFilterEntry( + std::unique_ptr<QueryCacheContext> query_cache_context, + disk_cache::EntryResult result); + void QueryCacheDidReadMetadata( + std::unique_ptr<QueryCacheContext> query_cache_context, + disk_cache::ScopedEntryPtr entry, + std::unique_ptr<proto::CacheMetadata> metadata); + void QueryCacheUpgradePadding( + std::unique_ptr<QueryCacheContext> query_cache_context, + disk_cache::ScopedEntryPtr entry, + std::unique_ptr<proto::CacheMetadata> metadata); + static bool QueryCacheResultCompare(const QueryCacheResult& lhs, + const QueryCacheResult& rhs); + static size_t EstimatedResponseSizeWithoutBlob( + const blink::mojom::FetchAPIResponse& response); + + // Match callbacks + void MatchImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageSchedulerPriority priority, + ResponseCallback callback); + void MatchDidMatchAll( + ResponseCallback callback, + blink::mojom::CacheStorageError match_all_error, + std::vector<blink::mojom::FetchAPIResponsePtr> match_all_responses); + + // MatchAll callbacks + void MatchAllImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + CacheStorageSchedulerPriority priority, + ResponsesCallback callback); + void MatchAllDidQueryCache( + ResponsesCallback callback, + int64_t trace_id, + blink::mojom::CacheStorageError error, + std::unique_ptr<QueryCacheResults> query_cache_results); + + // Utility method to write metadata headers to an entry. + using WriteMetadataCallback = + base::OnceCallback<void(int exepected_bytes, int rv)>; + void WriteMetadata(disk_cache::Entry* entry, + const proto::CacheMetadata& metadata, + WriteMetadataCallback callback); + + // WriteSideData callbacks + void WriteSideDataDidGetQuota(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len, + blink::mojom::QuotaStatusCode status_code, + int64_t usage, + int64_t quota); + + void WriteSideDataImpl(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len); + void WriteSideDataDidGetUsageAndQuota( + ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len, + blink::mojom::QuotaStatusCode status_code, + int64_t usage, + int64_t quota); + void WriteSideDataDidOpenEntry(ErrorCallback callback, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len, + disk_cache::EntryResult result); + void WriteSideDataDidReadMetaData( + ErrorCallback callback, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len, + ScopedWritableEntry entry, + std::unique_ptr<proto::CacheMetadata> headers); + void WriteSideDataDidWrite( + ErrorCallback callback, + ScopedWritableEntry entry, + int expected_bytes, + std::unique_ptr<content::proto::CacheMetadata> metadata, + int64_t trace_id, + int rv); + void WriteSideDataDidWriteMetadata(ErrorCallback callback, + ScopedWritableEntry entry, + int64_t padding, + int64_t side_data_padding, + int expected_bytes, + int rv); + void WriteSideDataComplete(ErrorCallback callback, + ScopedWritableEntry entry, + int64_t padding, + int64_t side_data_padding, + blink::mojom::CacheStorageError error); + + // Puts the request and response object in the cache. The response body (if + // present) is stored in the cache, but not the request body. Returns OK on + // success. + void Put(blink::mojom::BatchOperationPtr operation, + int64_t trace_id, + ErrorCallback callback); + void PutImpl(std::unique_ptr<PutContext> put_context); + void PutDidDeleteEntry(std::unique_ptr<PutContext> put_context, + blink::mojom::CacheStorageError error); + void PutDidGetUsageAndQuota(std::unique_ptr<PutContext> put_context, + blink::mojom::QuotaStatusCode status_code, + int64_t usage, + int64_t quota); + void PutDidCreateEntry(std::unique_ptr<PutContext> put_context, + disk_cache::EntryResult result); + void PutDidWriteHeaders(std::unique_ptr<PutContext> put_context, + int64_t padding, + int64_t side_data_padding, + int expected_bytes, + int rv); + void PutWriteBlobToCache(std::unique_ptr<PutContext> put_context, + int disk_cache_body_index); + void PutDidWriteBlobToCache(std::unique_ptr<PutContext> put_context, + BlobToDiskCacheIDMap::KeyType blob_to_cache_key, + int disk_cache_body_index, + ScopedWritableEntry entry, + bool success); + void PutWriteBlobToCacheComplete(std::unique_ptr<PutContext> put_context, + int disk_cache_body_index, + ScopedWritableEntry entry, + int rv); + void PutComplete(std::unique_ptr<PutContext> put_context, + blink::mojom::CacheStorageError error); + + // Asynchronously calculates the current cache size, notifies the quota + // manager of any change from the last report, and sets cache_size_ to the new + // size. + void UpdateCacheSize(base::OnceClosure callback); + void UpdateCacheSizeGotSize(CacheStorageCacheHandle, + base::OnceClosure callback, + int64_t current_cache_size); + void UpdateCacheSizeNotifiedStorageModified(base::OnceClosure callback); + + // GetAllMatchedEntries callbacks. + void GetAllMatchedEntriesImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + CacheEntriesCallback callback); + void GetAllMatchedEntriesDidQueryCache( + int64_t trace_id, + CacheEntriesCallback callback, + blink::mojom::CacheStorageError error, + std::unique_ptr<QueryCacheResults> query_cache_results); + + // Returns ERROR_NOT_FOUND if not found. Otherwise deletes and returns OK. + void Delete(blink::mojom::BatchOperationPtr operation, + ErrorCallback callback); + void DeleteImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + ErrorCallback callback); + void DeleteDidQueryCache( + ErrorCallback callback, + blink::mojom::CacheStorageError error, + std::unique_ptr<QueryCacheResults> query_cache_results); + + // Keys callbacks. + void KeysImpl(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback); + void KeysDidQueryCache( + RequestsCallback callback, + int64_t trace_id, + blink::mojom::CacheStorageError error, + std::unique_ptr<QueryCacheResults> query_cache_results); + + void CloseImpl(base::OnceClosure callback); + + void SizeImpl(SizeCallback callback); + + void GetSizeThenCloseDidGetSize(SizeCallback callback, int64_t cache_size); + + // Loads the backend and calls the callback with the result (true for + // success). The callback will always be called. Virtual for tests. + virtual void CreateBackend(ErrorCallback callback); + void CreateBackendDidCreate(ErrorCallback callback, + std::unique_ptr<ScopedBackendPtr> backend_ptr, + int rv); + + // Calculate the size and padding of the cache. + void CalculateCacheSizePadding(SizePaddingCallback callback); + void CalculateCacheSizePaddingGotSize(SizePaddingCallback callback, + int64_t cache_size); + void PaddingDidQueryCache( + SizePaddingCallback callback, + int64_t cache_size, + blink::mojom::CacheStorageError error, + std::unique_ptr<QueryCacheResults> query_cache_results); + + // Calculate the size (but not padding) of the cache. + void CalculateCacheSize(net::Int64CompletionOnceCallback callback); + + void InitBackend(); + void InitDidCreateBackend(base::OnceClosure callback, + blink::mojom::CacheStorageError cache_create_error); + void InitGotCacheSize(base::OnceClosure callback, + blink::mojom::CacheStorageError cache_create_error, + int64_t cache_size); + void InitGotCacheSizeAndPadding( + base::OnceClosure callback, + blink::mojom::CacheStorageError cache_create_error, + int64_t cache_size, + int64_t cache_padding); + void DeleteBackendCompletedIO(); + + // Calculate the required safe space to put the entry in the cache. + base::CheckedNumeric<uint64_t> CalculateRequiredSafeSpaceForPut( + const blink::mojom::BatchOperationPtr& operation); + base::CheckedNumeric<uint64_t> CalculateRequiredSafeSpaceForRequest( + const blink::mojom::FetchAPIRequestPtr& request); + base::CheckedNumeric<uint64_t> CalculateRequiredSafeSpaceForResponse( + const blink::mojom::FetchAPIResponsePtr& response); + + // Wrap |callback| in order to reference a CacheStorageCacheHandle + // for the duration of an asynchronous operation. We must keep this + // self reference for a couple reasons. First, we must allow any writes + // to cleanly complete in order to avoid truncated entries. In addition, + // we must keep the cache and its disk_cache backend alive until all + // open Entry objects are destroyed to avoid having a second backend + // opened by another CacheStorageCache clobbering the entries. + template <typename... Args> + base::OnceCallback<void(Args...)> WrapCallbackWithHandle( + base::OnceCallback<void(Args...)> callback) { + return base::BindOnce(&CacheStorageCache::RunWithHandle<Args...>, + weak_ptr_factory_.GetWeakPtr(), CreateHandle(), + std::move(callback)); + } + + // Invoked by wrapped callbacks with the CacheStorageCacheHandle passed + // as a parameter. The handle is kept alive here simply to maintain + // a self-reference during the operation. + template <typename... Args> + void RunWithHandle(CacheStorageCacheHandle handle, + base::OnceCallback<void(Args...)> callback, + Args... args) { + std::move(callback).Run(std::forward<Args>(args)...); + // |handle| is destroyed after running the inner wrapped callback. + } + + // Be sure to check |backend_state_| before use. + std::unique_ptr<disk_cache::Backend> backend_; + + blink::StorageKey storage_key_; + storage::mojom::CacheStorageOwner owner_; + const std::string cache_name_; + base::FilePath path_; + + // Raw pointer is safe because the CacheStorage instance owns this + // CacheStorageCache object. + raw_ptr<CacheStorage> cache_storage_; + + // A handle that is used to keep the owning CacheStorage instance referenced + // as long this cache object is also referenced. + CacheStorageHandle cache_storage_handle_; + + const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; + BackendState backend_state_ = BACKEND_UNINITIALIZED; + std::unique_ptr<CacheStorageScheduler> scheduler_; + bool initializing_ = false; + // The actual cache size (not including padding). + int64_t cache_size_; + int64_t cache_padding_ = 0; + int64_t last_reported_size_ = 0; + size_t max_query_size_bytes_; + size_t handle_ref_count_ = 0; + int query_cache_recursive_depth_ = 0; + raw_ptr<CacheStorageCacheObserver> cache_observer_; + std::unique_ptr<CacheStorageCacheEntryHandler> cache_entry_handler_; + + // Owns the elements of the list + BlobToDiskCacheIDMap active_blob_to_disk_cache_writers_; + + // Whether or not to store data in disk or memory. + bool memory_only_; + + // Active while waiting for the backend to finish its closing up, and contains + // the callback passed to CloseImpl. + base::OnceClosure post_backend_closed_callback_; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<CacheStorageCache> weak_ptr_factory_{this}; }; } // namespace content
diff --git a/content/browser/cache_storage/cache_storage_cache_entry_handler.cc b/content/browser/cache_storage/cache_storage_cache_entry_handler.cc index e1684e87..916c503 100644 --- a/content/browser/cache_storage/cache_storage_cache_entry_handler.cc +++ b/content/browser/cache_storage/cache_storage_cache_entry_handler.cc
@@ -8,8 +8,8 @@ #include "base/guid.h" #include "components/services/storage/public/mojom/blob_storage_context.mojom.h" #include "content/browser/cache_storage/background_fetch_cache_entry_handler_impl.h" +#include "content/browser/cache_storage/cache_storage.h" #include "content/browser/cache_storage/cache_storage_manager.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage.h" #include "content/public/browser/browser_task_traits.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/filter/source_stream.h"
diff --git a/content/browser/cache_storage/cache_storage_cache_observer.h b/content/browser/cache_storage/cache_storage_cache_observer.h index edb67486..4bac2000 100644 --- a/content/browser/cache_storage/cache_storage_cache_observer.h +++ b/content/browser/cache_storage/cache_storage_cache_observer.h
@@ -7,12 +7,12 @@ namespace content { -class LegacyCacheStorageCache; +class CacheStorageCache; class CacheStorageCacheObserver { public: // The cache size has been set. - virtual void CacheSizeUpdated(const LegacyCacheStorageCache* cache) = 0; + virtual void CacheSizeUpdated(const CacheStorageCache* cache) = 0; }; } // namespace content
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc index 77d02a4..2657948 100644 --- a/content/browser/cache_storage/cache_storage_cache_unittest.cc +++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -29,12 +29,11 @@ #include "build/build_config.h" #include "components/services/storage/public/mojom/cache_storage_control.mojom.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h" +#include "content/browser/cache_storage/cache_storage.h" #include "content/browser/cache_storage/cache_storage_cache.h" #include "content/browser/cache_storage/cache_storage_cache_handle.h" #include "content/browser/cache_storage/cache_storage_histogram_utils.h" #include "content/browser/cache_storage/cache_storage_manager.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage_cache.h" #include "content/common/background_fetch/background_fetch_types.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/browser_task_environment.h" @@ -418,25 +417,25 @@ } // A CacheStorageCache that can optionally delay during backend creation. -class TestCacheStorageCache : public LegacyCacheStorageCache { +class TestCacheStorageCache : public CacheStorageCache { public: TestCacheStorageCache( const blink::StorageKey& storage_key, const std::string& cache_name, const base::FilePath& path, - LegacyCacheStorage* cache_storage, + CacheStorage* cache_storage, const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, scoped_refptr<BlobStorageContextWrapper> blob_storage_context) - : LegacyCacheStorageCache(storage_key, - storage::mojom::CacheStorageOwner::kCacheAPI, - cache_name, - path, - cache_storage, - base::ThreadTaskRunnerHandle::Get(), - quota_manager_proxy, - std::move(blob_storage_context), - 0 /* cache_size */, - 0 /* cache_padding */), + : CacheStorageCache(storage_key, + storage::mojom::CacheStorageOwner::kCacheAPI, + cache_name, + path, + cache_storage, + base::ThreadTaskRunnerHandle::Get(), + quota_manager_proxy, + std::move(blob_storage_context), + 0 /* cache_size */, + 0 /* cache_padding */), delay_backend_creation_(false) {} TestCacheStorageCache(const TestCacheStorageCache&) = delete; @@ -452,8 +451,7 @@ } void ContinueCreateBackend() { - LegacyCacheStorageCache::CreateBackend( - std::move(backend_creation_callback_)); + CacheStorageCache::CreateBackend(std::move(backend_creation_callback_)); } void set_delay_backend_creation(bool delay) { @@ -494,30 +492,30 @@ ErrorCallback backend_creation_callback_; }; -class MockLegacyCacheStorage : public LegacyCacheStorage { +class MockCacheStorage : public CacheStorage { public: - MockLegacyCacheStorage( + MockCacheStorage( const base::FilePath& origin_path, bool memory_only, base::SequencedTaskRunner* cache_task_runner, scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - LegacyCacheStorageManager* cache_storage_manager, + CacheStorageManager* cache_storage_manager, const blink::StorageKey& storage_key, storage::mojom::CacheStorageOwner owner) - : LegacyCacheStorage(origin_path, - memory_only, - cache_task_runner, - std::move(scheduler_task_runner), - std::move(quota_manager_proxy), - std::move(blob_storage_context), - cache_storage_manager, - storage_key, - owner) {} + : CacheStorage(origin_path, + memory_only, + cache_task_runner, + std::move(scheduler_task_runner), + std::move(quota_manager_proxy), + std::move(blob_storage_context), + cache_storage_manager, + storage_key, + owner) {} - void CacheUnreferenced(LegacyCacheStorageCache* cache) override { - // Normally the LegacyCacheStorage will attempt to delete the cache + void CacheUnreferenced(CacheStorageCache* cache) override { + // Normally the CacheStorage will attempt to delete the cache // from its map when the cache has become unreferenced. Since we are // using detached cache objects we instead override to do nothing here. } @@ -566,10 +564,10 @@ std::vector<uint8_t>(expected_blob_data_.begin(), expected_blob_data_.end())); - // Use a mock LegacyCacheStorage object so we can use real - // CacheStorageCacheHandle reference counting. A LegacyCacheStorage + // Use a mock CacheStorage object so we can use real + // CacheStorageCacheHandle reference counting. A CacheStorage // must be present to be notified when a cache becomes unreferenced. - mock_cache_storage_ = std::make_unique<MockLegacyCacheStorage>( + mock_cache_storage_ = std::make_unique<MockCacheStorage>( temp_dir_path_, MemoryOnly(), base::ThreadTaskRunnerHandle::Get().get(), base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_, blob_storage_context_, /* cache_storage_manager = */ nullptr, @@ -600,7 +598,7 @@ return kTestUrl.ReplaceComponents(replacements); } - void InitCache(LegacyCacheStorage* cache_storage) { + void InitCache(CacheStorage* cache_storage) { cache_ = std::make_unique<TestCacheStorageCache>( blink::StorageKey(url::Origin::Create(kTestUrl)), kCacheName, temp_dir_path_, cache_storage, quota_manager_proxy_, @@ -983,7 +981,7 @@ size_t EstimatedResponseSizeWithoutBlob( const blink::mojom::FetchAPIResponse& response) { - return LegacyCacheStorageCache::EstimatedResponseSizeWithoutBlob(response); + return CacheStorageCache::EstimatedResponseSizeWithoutBlob(response); } protected: @@ -994,7 +992,7 @@ scoped_refptr<storage::MockQuotaManager> mock_quota_manager_; scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_; scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; - std::unique_ptr<MockLegacyCacheStorage> mock_cache_storage_; + std::unique_ptr<MockCacheStorage> mock_cache_storage_; base::FilePath temp_dir_path_; std::unique_ptr<TestCacheStorageCache> cache_; @@ -1082,9 +1080,8 @@ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse())); EXPECT_TRUE(Match(no_body_request_)); - size_t max_size = - LegacyCacheStorageCache::EstimatedStructSize(no_body_request_) + - EstimatedResponseSizeWithoutBlob(*callback_response_); + size_t max_size = CacheStorageCache::EstimatedStructSize(no_body_request_) + + EstimatedResponseSizeWithoutBlob(*callback_response_); SetMaxQuerySizeBytes(max_size); EXPECT_TRUE(Match(no_body_request_)); @@ -1099,10 +1096,10 @@ EXPECT_TRUE(Match(body_request_)); size_t body_request_size = - LegacyCacheStorageCache::EstimatedStructSize(body_request_) + + CacheStorageCache::EstimatedStructSize(body_request_) + EstimatedResponseSizeWithoutBlob(*callback_response_); size_t query_request_size = - LegacyCacheStorageCache::EstimatedStructSize(body_request_with_query_) + + CacheStorageCache::EstimatedStructSize(body_request_with_query_) + EstimatedResponseSizeWithoutBlob(*callback_response_); std::vector<blink::mojom::FetchAPIResponsePtr> responses; @@ -1133,14 +1130,13 @@ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse())); EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse())); - size_t max_size = - LegacyCacheStorageCache::EstimatedStructSize(no_body_request_) + - LegacyCacheStorageCache::EstimatedStructSize(body_request_); + size_t max_size = CacheStorageCache::EstimatedStructSize(no_body_request_) + + CacheStorageCache::EstimatedStructSize(body_request_); SetMaxQuerySizeBytes(max_size); EXPECT_TRUE(Keys()); SetMaxQuerySizeBytes( - LegacyCacheStorageCache::EstimatedStructSize(no_body_request_)); + CacheStorageCache::EstimatedStructSize(no_body_request_)); EXPECT_FALSE(Keys()); EXPECT_EQ(CacheStorageError::kErrorQueryTooLarge, callback_error_); }
diff --git a/content/browser/cache_storage/cache_storage_context_impl.cc b/content/browser/cache_storage/cache_storage_context_impl.cc index 565ae0f..7bd7e9ce 100644 --- a/content/browser/cache_storage/cache_storage_context_impl.cc +++ b/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -17,8 +17,8 @@ #include "components/services/storage/public/mojom/storage_usage_info.mojom.h" #include "content/browser/cache_storage/blob_storage_context_wrapper.h" #include "content/browser/cache_storage/cache_storage_dispatcher_host.h" +#include "content/browser/cache_storage/cache_storage_manager.h" #include "content/browser/cache_storage/cache_storage_quota_client.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" @@ -79,7 +79,7 @@ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); DCHECK(!cache_manager_); - cache_manager_ = LegacyCacheStorageManager::Create( + cache_manager_ = CacheStorageManager::Create( user_data_directory, std::move(cache_task_runner), base::SequencedTaskRunnerHandle::Get(), quota_manager_proxy_, base::MakeRefCounted<BlobStorageContextWrapper>(
diff --git a/content/browser/cache_storage/cache_storage_manager.cc b/content/browser/cache_storage/cache_storage_manager.cc index 1160020..65d3088 100644 --- a/content/browser/cache_storage/cache_storage_manager.cc +++ b/content/browser/cache_storage/cache_storage_manager.cc
@@ -4,10 +4,587 @@ #include "content/browser/cache_storage/cache_storage_manager.h" +#include <stdint.h> + +#include <map> +#include <numeric> +#include <set> +#include <utility> + +#include "base/barrier_closure.h" +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/containers/id_map.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_util.h" +#include "base/hash/sha1.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/task/sequenced_task_runner.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/time/time.h" +#include "components/services/storage/public/cpp/constants.h" +#include "content/browser/cache_storage/cache_storage.h" +#include "content/browser/cache_storage/cache_storage.pb.h" +#include "content/browser/cache_storage/cache_storage_quota_client.h" +#include "storage/browser/quota/quota_manager_proxy.h" +#include "storage/common/database/database_identifier.h" #include "third_party/blink/public/common/storage_key/storage_key.h" +#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" +#include "url/gurl.h" +#include "url/origin.h" namespace content { +namespace { + +bool DeleteDir(const base::FilePath& path) { + return base::DeletePathRecursively(path); +} + +void DeleteStorageKeyDidDeleteDir( + storage::mojom::QuotaClient::DeleteBucketDataCallback callback, + bool rv) { + // On scheduler sequence. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), + rv ? blink::mojom::QuotaStatusCode::kOk + : blink::mojom::QuotaStatusCode::kErrorAbort)); +} + +// Calculate the sum of all cache sizes in this store, but only if all sizes are +// known. If one or more sizes are not known then return kSizeUnknown. +int64_t GetCacheStorageSize(const base::FilePath& base_path, + const base::Time& index_time, + const proto::CacheStorageIndex& index) { + // Note, do not use the base path time modified to invalidate the index file. + // On some platforms the directory modified time will be slightly later than + // the last modified time of a file within it. This means any write to the + // index file will also update the directory modify time slightly after + // immediately invalidating it. To avoid this we only look at the cache + // directories and not the base directory containing the index itself. + int64_t storage_size = 0; + for (int i = 0, max = index.cache_size(); i < max; ++i) { + const proto::CacheStorageIndex::Cache& cache = index.cache(i); + if (!cache.has_cache_dir() || !cache.has_size() || + cache.size() == CacheStorage::kSizeUnknown || !cache.has_padding() || + cache.padding() == CacheStorage::kSizeUnknown) { + return CacheStorage::kSizeUnknown; + } + + // Check the modified time on each cache directory. If one of the + // directories has the same or newer modified time as the index file, then + // its size is most likely not accounted for in the index file. The + // cache can have a newer time here in spite of our base path time check + // above since simple disk_cache writes to these directories from a + // different thread. + base::FilePath path = base_path.AppendASCII(cache.cache_dir()); + base::File::Info file_info; + if (!base::GetFileInfo(path, &file_info) || + file_info.last_modified >= index_time) { + return CacheStorage::kSizeUnknown; + } + + storage_size += (cache.size() + cache.padding()); + } + + return storage_size; +} + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class IndexResult { + kOk = 0, + kFailedToParse = 1, + kMissingOrigin = 2, + kEmptyOriginUrl = 3, + kPathMismatch = 4, + kPathFileInfoFailed = 5, + // Add new enums above + kMaxValue = kPathFileInfoFailed, +}; + +IndexResult ValidateIndex(proto::CacheStorageIndex index) { + if (!index.has_origin()) + return IndexResult::kMissingOrigin; + + GURL url(index.origin()); + if (url.is_empty()) + return IndexResult::kEmptyOriginUrl; + + return IndexResult::kOk; +} + +void RecordIndexValidationResult(IndexResult value) { + base::UmaHistogramEnumeration("ServiceWorkerCache.ListOriginsIndexValidity", + value); +} + +// Open the various cache directories' index files and extract their storage +// keys, sizes (if current), and last modified times. +std::vector<storage::mojom::StorageUsageInfoPtr> +GetStorageKeysAndLastModifiedOnTaskRunner( + std::vector<storage::mojom::StorageUsageInfoPtr> usages, + base::FilePath root_path, + storage::mojom::CacheStorageOwner owner) { + base::FileEnumerator file_enum(root_path, false /* recursive */, + base::FileEnumerator::DIRECTORIES); + + base::FilePath path; + while (!(path = file_enum.Next()).empty()) { + base::FilePath index_path = path.AppendASCII(CacheStorage::kIndexFileName); + base::File::Info file_info; + base::Time index_last_modified; + if (GetFileInfo(index_path, &file_info)) + index_last_modified = file_info.last_modified; + std::string protobuf; + base::ReadFileToString(path.AppendASCII(CacheStorage::kIndexFileName), + &protobuf); + + proto::CacheStorageIndex index; + if (!index.ParseFromString(protobuf)) { + RecordIndexValidationResult(IndexResult::kFailedToParse); + continue; + } + + IndexResult rv = ValidateIndex(index); + if (rv != IndexResult::kOk) { + RecordIndexValidationResult(rv); + continue; + } + + auto storage_key = + blink::StorageKey(url::Origin::Create(GURL(index.origin()))); + DCHECK(!storage_key.origin().GetURL().is_empty()); + + auto origin_path = CacheStorageManager::ConstructStorageKeyPath( + root_path, storage_key, owner); + if (path != origin_path) { + storage::mojom::CacheStorageOwner other_owner = + owner == storage::mojom::CacheStorageOwner::kCacheAPI + ? storage::mojom::CacheStorageOwner::kBackgroundFetch + : storage::mojom::CacheStorageOwner::kCacheAPI; + auto other_owner_path = CacheStorageManager::ConstructStorageKeyPath( + root_path, storage_key, other_owner); + // Some of the paths in the |root_path| directory are for a different + // |owner|. That is valid and expected, but if the path doesn't match + // the calculated path for either |owner|, then it is invalid. + if (path != other_owner_path) + RecordIndexValidationResult(IndexResult::kPathMismatch); + continue; + } + + int64_t storage_size = + GetCacheStorageSize(path, index_last_modified, index); + + usages.emplace_back(storage::mojom::StorageUsageInfo::New( + storage_key.origin(), storage_size, file_info.last_modified)); + RecordIndexValidationResult(IndexResult::kOk); + } + + return usages; +} + +std::vector<blink::StorageKey> ListStorageKeysOnTaskRunner( + base::FilePath root_path, + storage::mojom::CacheStorageOwner owner) { + std::vector<storage::mojom::StorageUsageInfoPtr> usages = + GetStorageKeysAndLastModifiedOnTaskRunner( + std::vector<storage::mojom::StorageUsageInfoPtr>(), root_path, owner); + + std::vector<blink::StorageKey> out_storage_keys; + for (const storage::mojom::StorageUsageInfoPtr& usage : usages) + out_storage_keys.emplace_back(blink::StorageKey(usage->origin)); + + return out_storage_keys; +} + +void AllOriginSizesReported( + std::vector<storage::mojom::StorageUsageInfoPtr> usages, + storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback + callback) { + // On scheduler sequence. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), std::move(usages))); +} + +void OneOriginSizeReported(base::OnceClosure callback, + storage::mojom::StorageUsageInfoPtr* usage, + int64_t size) { + // On scheduler sequence. + DCHECK_NE(size, CacheStorage::kSizeUnknown); + (*usage)->total_size_bytes = size; + base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(callback)); +} + +} // namespace + +// static +scoped_refptr<CacheStorageManager> CacheStorageManager::Create( + const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context) { + DCHECK(cache_task_runner); + DCHECK(scheduler_task_runner); + DCHECK(quota_manager_proxy); + DCHECK(blob_storage_context); + + base::FilePath root_path = path; + if (!path.empty()) { + root_path = path.Append(storage::kServiceWorkerDirectory) + .AppendASCII("CacheStorage"); + } + + return base::WrapRefCounted(new CacheStorageManager( + root_path, std::move(cache_task_runner), std::move(scheduler_task_runner), + std::move(quota_manager_proxy), std::move(blob_storage_context))); +} + +// static +scoped_refptr<CacheStorageManager> CacheStorageManager::CreateForTesting( + CacheStorageManager* old_manager) { + scoped_refptr<CacheStorageManager> manager(new CacheStorageManager( + old_manager->root_path(), old_manager->cache_task_runner(), + old_manager->scheduler_task_runner(), old_manager->quota_manager_proxy_, + old_manager->blob_storage_context_)); + return manager; +} + +CacheStorageManager::~CacheStorageManager() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +CacheStorageHandle CacheStorageManager::OpenCacheStorage( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Wait to create the MemoryPressureListener until the first CacheStorage + // object is needed. This ensures we create the listener on the correct + // thread. + if (!memory_pressure_listener_) { + memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( + FROM_HERE, base::BindRepeating(&CacheStorageManager::OnMemoryPressure, + base::Unretained(this))); + } + + CacheStorageMap::const_iterator it = + cache_storage_map_.find({storage_key, owner}); + if (it == cache_storage_map_.end()) { + CacheStorage* cache_storage = new CacheStorage( + ConstructStorageKeyPath(root_path_, storage_key, owner), + IsMemoryBacked(), cache_task_runner_.get(), scheduler_task_runner_, + quota_manager_proxy_, blob_storage_context_, this, storage_key, owner); + cache_storage_map_[{storage_key, owner}] = base::WrapUnique(cache_storage); + return cache_storage->CreateHandle(); + } + return it->second.get()->CreateHandle(); +} + +void CacheStorageManager::NotifyCacheListChanged( + const blink::StorageKey& storage_key) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (const auto& observer : observers_) + observer->OnCacheListChanged(storage_key); +} + +void CacheStorageManager::NotifyCacheContentChanged( + const blink::StorageKey& storage_key, + const std::string& name) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (const auto& observer : observers_) + observer->OnCacheContentChanged(storage_key, name); +} + +void CacheStorageManager::CacheStorageUnreferenced( + CacheStorage* cache_storage, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(cache_storage); + cache_storage->AssertUnreferenced(); + auto it = cache_storage_map_.find({storage_key, owner}); + DCHECK(it != cache_storage_map_.end()); + DCHECK(it->second.get() == cache_storage); + + // Currently we don't do anything when a CacheStorage instance becomes + // unreferenced. In the future we will deallocate some or all of the + // CacheStorage's state. +} + +void CacheStorageManager::GetAllStorageKeysUsage( + storage::mojom::CacheStorageOwner owner, + storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback + callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + std::vector<storage::mojom::StorageUsageInfoPtr> usages; + + if (IsMemoryBacked()) { + for (const auto& storage_keys_details : cache_storage_map_) { + if (storage_keys_details.first.second != owner) + continue; + usages.emplace_back(storage::mojom::StorageUsageInfo::New( + storage_keys_details.first.first.origin(), + /*total_size_bytes=*/0, + /*last_modified=*/base::Time())); + } + GetAllStorageKeysUsageGetSizes(std::move(callback), std::move(usages)); + return; + } + + cache_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&GetStorageKeysAndLastModifiedOnTaskRunner, + std::move(usages), root_path_, owner), + base::BindOnce(&CacheStorageManager::GetAllStorageKeysUsageGetSizes, + base::WrapRefCounted(this), std::move(callback))); +} + +void CacheStorageManager::GetAllStorageKeysUsageGetSizes( + storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback callback, + std::vector<storage::mojom::StorageUsageInfoPtr> usages) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // The origin GURL and last modified times are set in |usages| but not the + // size in bytes. Call each CacheStorage's Size() function to fill that out. + + if (usages.empty()) { + scheduler_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), std::move(usages))); + return; + } + + auto* usages_ptr = &usages[0]; + size_t usages_count = usages.size(); + base::RepeatingClosure barrier_closure = base::BarrierClosure( + usages_count, base::BindOnce(&AllOriginSizesReported, std::move(usages), + std::move(callback))); + + for (size_t i = 0; i < usages_count; ++i) { + auto& usage = usages_ptr[i]; + if (usage->total_size_bytes != CacheStorage::kSizeUnknown || + !IsValidQuotaStorageKey(blink::StorageKey(usage->origin))) { + scheduler_task_runner_->PostTask(FROM_HERE, barrier_closure); + continue; + } + CacheStorageHandle cache_storage = + OpenCacheStorage(blink::StorageKey(usage->origin), + storage::mojom::CacheStorageOwner::kCacheAPI); + CacheStorage::From(cache_storage) + ->Size(base::BindOnce(&OneOriginSizeReported, barrier_closure, &usage)); + } +} + +void CacheStorageManager::GetStorageKeyUsage( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::GetBucketUsageCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (IsMemoryBacked()) { + auto it = cache_storage_map_.find({storage_key, owner}); + if (it == cache_storage_map_.end()) { + scheduler_task_runner_->PostTask(FROM_HERE, + base::BindOnce(std::move(callback), + /*usage=*/0)); + return; + } + CacheStorageHandle cache_storage = OpenCacheStorage(storage_key, owner); + CacheStorage::From(cache_storage)->Size(std::move(callback)); + return; + } + cache_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&base::PathExists, + ConstructStorageKeyPath(root_path_, storage_key, owner)), + base::BindOnce(&CacheStorageManager::GetStorageKeyUsageDidGetExists, + base::WrapRefCounted(this), storage_key, owner, + std::move(callback))); +} + +void CacheStorageManager::GetStorageKeyUsageDidGetExists( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::GetBucketUsageCallback callback, + bool exists) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!exists) { + scheduler_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), /*usage=*/0)); + return; + } + CacheStorageHandle cache_storage = OpenCacheStorage(storage_key, owner); + CacheStorage::From(cache_storage)->Size(std::move(callback)); +} + +void CacheStorageManager::GetStorageKeys( + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::GetStorageKeysForTypeCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (IsMemoryBacked()) { + std::vector<blink::StorageKey> storage_keys; + for (const auto& key_value : cache_storage_map_) + if (key_value.first.second == owner) + storage_keys.push_back(key_value.first.first); + + scheduler_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), std::move(storage_keys))); + return; + } + + PostTaskAndReplyWithResult( + cache_task_runner_.get(), FROM_HERE, + base::BindOnce(&ListStorageKeysOnTaskRunner, root_path_, owner), + std::move(callback)); +} + +void CacheStorageManager::DeleteStorageKeyData( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::DeleteBucketDataCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (IsMemoryBacked()) { + auto it = cache_storage_map_.find({storage_key, owner}); + if (it == cache_storage_map_.end()) { + scheduler_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + blink::mojom::QuotaStatusCode::kOk)); + return; + } + DeleteStorageKeyDataDidGetExists(storage_key, owner, std::move(callback), + /*exists=*/true); + return; + } + + cache_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&base::PathExists, + ConstructStorageKeyPath(root_path_, storage_key, owner)), + base::BindOnce(&CacheStorageManager::DeleteStorageKeyDataDidGetExists, + base::WrapRefCounted(this), storage_key, owner, + std::move(callback))); +} + +void CacheStorageManager::DeleteStorageKeyDataDidGetExists( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::DeleteBucketDataCallback callback, + bool exists) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!exists) { + scheduler_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + blink::mojom::QuotaStatusCode::kOk)); + return; + } + + // Create the CacheStorage for the storage key if it hasn't been loaded yet. + CacheStorageHandle handle = OpenCacheStorage(storage_key, owner); + + auto it = cache_storage_map_.find({storage_key, owner}); + DCHECK(it != cache_storage_map_.end()); + + CacheStorage* cache_storage = it->second.release(); + cache_storage->ResetManager(); + cache_storage_map_.erase({storage_key, owner}); + cache_storage->GetSizeThenCloseAllCaches( + base::BindOnce(&CacheStorageManager::DeleteStorageKeyDidClose, + base::WrapRefCounted(this), storage_key, owner, + std::move(callback), base::WrapUnique(cache_storage))); +} + +void CacheStorageManager::DeleteStorageKeyData( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DeleteStorageKeyData(storage_key, owner, base::DoNothing()); +} + +void CacheStorageManager::AddObserver( + mojo::PendingRemote<storage::mojom::CacheStorageObserver> observer) { + observers_.Add(std::move(observer)); +} + +void CacheStorageManager::DeleteStorageKeyDidClose( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::DeleteBucketDataCallback callback, + std::unique_ptr<CacheStorage> cache_storage, + int64_t origin_size) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // TODO(jkarlin): Deleting the storage leaves any unfinished operations + // hanging, resulting in unresolved promises. Fix this by returning early from + // CacheStorage operations posted after GetSizeThenCloseAllCaches is called. + cache_storage.reset(); + + quota_manager_proxy_->NotifyStorageModified( + CacheStorageQuotaClient::GetClientTypeFromOwner(owner), storage_key, + blink::mojom::StorageType::kTemporary, -origin_size, base::Time::Now(), + base::SequencedTaskRunnerHandle::Get(), base::DoNothing()); + + if (owner == storage::mojom::CacheStorageOwner::kCacheAPI) + NotifyCacheListChanged(storage_key); + + if (IsMemoryBacked()) { + scheduler_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + blink::mojom::QuotaStatusCode::kOk)); + return; + } + + PostTaskAndReplyWithResult( + cache_task_runner_.get(), FROM_HERE, + base::BindOnce(&DeleteDir, + ConstructStorageKeyPath(root_path_, storage_key, owner)), + base::BindOnce(&DeleteStorageKeyDidDeleteDir, std::move(callback))); +} + +CacheStorageManager::CacheStorageManager( + const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context) + : root_path_(path), + cache_task_runner_(std::move(cache_task_runner)), + scheduler_task_runner_(std::move(scheduler_task_runner)), + quota_manager_proxy_(std::move(quota_manager_proxy)), + blob_storage_context_(std::move(blob_storage_context)) { + DCHECK(cache_task_runner_); + DCHECK(scheduler_task_runner_); + DCHECK(quota_manager_proxy_); + DCHECK(blob_storage_context_); +} + +// static +base::FilePath CacheStorageManager::ConstructStorageKeyPath( + const base::FilePath& root_path, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner) { + // TODO(https://crbug.com/1199077): This identifier needs to be updated to + // include the full serialization of `storage_key`. + std::string identifier = + storage::GetIdentifierFromOrigin(storage_key.origin()); + if (owner != storage::mojom::CacheStorageOwner::kCacheAPI) { + identifier += "-" + std::to_string(static_cast<int>(owner)); + } + const std::string origin_hash = base::SHA1HashString(identifier); + const std::string origin_hash_hex = base::ToLowerASCII( + base::HexEncode(origin_hash.c_str(), origin_hash.length())); + return root_path.AppendASCII(origin_hash_hex); +} + // static bool CacheStorageManager::IsValidQuotaStorageKey( const blink::StorageKey& storage_key) { @@ -16,4 +593,15 @@ return !storage_key.origin().opaque(); } +void CacheStorageManager::OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) + return; + + for (auto& entry : cache_storage_map_) { + entry.second->ReleaseUnreferencedCaches(); + } +} + } // namespace content
diff --git a/content/browser/cache_storage/cache_storage_manager.h b/content/browser/cache_storage/cache_storage_manager.h index f10d2d63..9135d657 100644 --- a/content/browser/cache_storage/cache_storage_manager.h +++ b/content/browser/cache_storage/cache_storage_manager.h
@@ -5,15 +5,39 @@ #ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_MANAGER_H_ #define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_MANAGER_H_ +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/memory/memory_pressure_listener.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequence_checker.h" #include "components/services/storage/public/mojom/cache_storage_control.mojom.h" #include "components/services/storage/public/mojom/quota_client.mojom.h" +#include "components/services/storage/public/mojom/storage_usage_info.mojom.h" +#include "content/browser/cache_storage/blob_storage_context_wrapper.h" +#include "content/browser/cache_storage/cache_storage.h" +#include "content/browser/cache_storage/cache_storage_cache.h" +#include "content/browser/cache_storage/cache_storage_context_impl.h" #include "content/browser/cache_storage/cache_storage_handle.h" #include "content/common/content_export.h" #include "content/public/browser/browser_thread.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/remote_set.h" #include "third_party/blink/public/common/storage_key/storage_key.h" +namespace base { +class SequencedTaskRunner; +} + namespace content { +namespace cache_storage_manager_unittest { +class CacheStorageManagerTest; +} + // Keeps track of a CacheStorage per StorageKey. There is one // CacheStorageManager per CacheStorageOwner. Created and accessed from a single // sequence. @@ -22,43 +46,144 @@ class CONTENT_EXPORT CacheStorageManager : public base::RefCounted<CacheStorageManager> { public: - // Open the CacheStorage for the given `storage_key` and `owner`. A reference - // counting handle is returned which can be stored and used similar to a weak - // pointer. - virtual CacheStorageHandle OpenCacheStorage( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) = 0; + static scoped_refptr<CacheStorageManager> Create( + const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context); - // QuotaClient and Browsing Data Deletion support. - virtual void GetAllStorageKeysUsage( - storage::mojom::CacheStorageOwner owner, - storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback - callback) = 0; - virtual void GetStorageKeyUsage( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetBucketUsageCallback callback) = 0; - virtual void GetStorageKeys( - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetStorageKeysForTypeCallback callback) = 0; - virtual void DeleteStorageKeyData( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback) = 0; - virtual void DeleteStorageKeyData( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) = 0; + // Create a new manager using the underlying configuration of the given + // manager, but with its own list of storage objects. This is only used + // for testing. + static scoped_refptr<CacheStorageManager> CreateForTesting( + CacheStorageManager* old_manager); - virtual void AddObserver( - mojo::PendingRemote<storage::mojom::CacheStorageObserver> observer) = 0; + CacheStorageManager(const CacheStorageManager&) = delete; + CacheStorageManager& operator=(const CacheStorageManager&) = delete; + + // Map a database identifier (computed from a storage key) to the path. + static base::FilePath ConstructStorageKeyPath( + const base::FilePath& root_path, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner); static bool IsValidQuotaStorageKey(const blink::StorageKey& storage_key); + // Open the CacheStorage for the given storage_key and owner. A reference + // counting handle is returned which can be stored and used similar to a weak + // pointer. + CacheStorageHandle OpenCacheStorage(const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner); + + // QuotaClient and Browsing Data Deletion support. + void GetAllStorageKeysUsage( + storage::mojom::CacheStorageOwner owner, + storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback + callback); + void GetStorageKeyUsage( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::GetBucketUsageCallback callback); + void GetStorageKeys( + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::GetStorageKeysForTypeCallback callback); + void DeleteStorageKeyData( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::DeleteBucketDataCallback callback); + void DeleteStorageKeyData(const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner); + void AddObserver( + mojo::PendingRemote<storage::mojom::CacheStorageObserver> observer); + + void NotifyCacheListChanged(const blink::StorageKey& storage_key); + void NotifyCacheContentChanged(const blink::StorageKey& storage_key, + const std::string& name); + + base::FilePath root_path() const { return root_path_; } + + // This method is called when the last CacheStorageHandle for a particular + // instance is destroyed and its reference count drops to zero. + void CacheStorageUnreferenced(CacheStorage* cache_storage, + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner); + protected: friend class base::RefCounted<CacheStorageManager>; - CacheStorageManager() = default; - virtual ~CacheStorageManager() = default; + CacheStorageManager( + const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + scoped_refptr<BlobStorageContextWrapper> blob_storage_context); + virtual ~CacheStorageManager(); + + private: + friend class cache_storage_manager_unittest::CacheStorageManagerTest; + friend class CacheStorageContextImpl; + + typedef std::map< + std::pair<blink::StorageKey, storage::mojom::CacheStorageOwner>, + std::unique_ptr<CacheStorage>> + CacheStorageMap; + + void GetAllStorageKeysUsageGetSizes( + storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback + callback, + std::vector<storage::mojom::StorageUsageInfoPtr> usage_info); + + void GetStorageKeyUsageDidGetExists( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::GetBucketUsageCallback callback, + bool exists); + + void DeleteStorageKeyDataDidGetExists( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::DeleteBucketDataCallback callback, + bool exists); + + void DeleteStorageKeyDidClose( + const blink::StorageKey& storage_key, + storage::mojom::CacheStorageOwner owner, + storage::mojom::QuotaClient::DeleteBucketDataCallback callback, + std::unique_ptr<CacheStorage> cache_storage, + int64_t origin_size); + + scoped_refptr<base::SequencedTaskRunner> cache_task_runner() const { + return cache_task_runner_; + } + + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner() const { + return scheduler_task_runner_; + } + + bool IsMemoryBacked() const { return root_path_.empty(); } + + // MemoryPressureListener callback + void OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level); + + base::FilePath root_path_; + const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; + const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; + + const scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; + + // The map owns the CacheStorages and the CacheStorages are only accessed on + // |cache_task_runner_|. + CacheStorageMap cache_storage_map_; + + mojo::RemoteSet<storage::mojom::CacheStorageObserver> observers_; + + const scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; + + std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; + + SEQUENCE_CHECKER(sequence_checker_); }; } // namespace content
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index 3776cdb4..a6d8915f 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -34,13 +34,13 @@ #include "components/services/storage/public/mojom/cache_storage_control.mojom.h" #include "components/services/storage/public/mojom/storage_usage_info.mojom.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h" +#include "content/browser/cache_storage/cache_storage.h" #include "content/browser/cache_storage/cache_storage.pb.h" #include "content/browser/cache_storage/cache_storage_cache_handle.h" #include "content/browser/cache_storage/cache_storage_context_impl.h" +#include "content/browser/cache_storage/cache_storage_manager.h" #include "content/browser/cache_storage/cache_storage_quota_client.h" #include "content/browser/cache_storage/cache_storage_scheduler.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h" #include "content/common/background_fetch/background_fetch_types.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/browser_task_environment.h" @@ -183,7 +183,7 @@ bool IsIndexFileCurrent(const base::FilePath& cache_dir) { base::File::Info info; const base::FilePath index_path = - cache_dir.AppendASCII(LegacyCacheStorage::kIndexFileName); + cache_dir.AppendASCII(CacheStorage::kIndexFileName); if (!GetFileInfo(index_path, &info)) return false; base::Time index_last_modified = info.last_modified; @@ -364,7 +364,7 @@ mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get()); - cache_manager_ = LegacyCacheStorageManager::Create( + cache_manager_ = CacheStorageManager::Create( temp_dir_path, base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_, blob_storage_context_); @@ -373,15 +373,14 @@ void RecreateStorageManager() { DCHECK(cache_manager_); auto* legacy_manager = - static_cast<LegacyCacheStorageManager*>(cache_manager_.get()); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(legacy_manager); + static_cast<CacheStorageManager*>(cache_manager_.get()); + cache_manager_ = CacheStorageManager::CreateForTesting(legacy_manager); } bool FlushCacheStorageIndex(const blink::StorageKey& storage_key) { callback_bool_ = false; base::RunLoop loop; - auto* impl = LegacyCacheStorage::From(CacheStorageForKey(storage_key)); + auto* impl = CacheStorage::From(CacheStorageForKey(storage_key)); bool write_was_scheduled = impl->InitiateScheduledIndexWriteForTest( base::BindOnce(&CacheStorageManagerTest::BoolCallback, base::Unretained(this), &loop)); @@ -739,7 +738,7 @@ int64_t GetSizeThenCloseAllCaches(const blink::StorageKey& storage_key) { base::RunLoop loop; CacheStorageHandle cache_storage = CacheStorageForKey(storage_key); - LegacyCacheStorage::From(cache_storage) + CacheStorage::From(cache_storage) ->GetSizeThenCloseAllCaches( base::BindOnce(&CacheStorageManagerTest::UsageCallback, base::Unretained(this), &loop)); @@ -750,7 +749,7 @@ int64_t Size(const blink::StorageKey& storage_key) { base::RunLoop loop; CacheStorageHandle cache_storage = CacheStorageForKey(storage_key); - LegacyCacheStorage::From(cache_storage) + CacheStorage::From(cache_storage) ->Size(base::BindOnce(&CacheStorageManagerTest::UsageCallback, base::Unretained(this), &loop)); loop.Run(); @@ -1178,8 +1177,8 @@ CacheStorageHandle cache_storage = CacheStorageForKey(storage_key1_); EXPECT_TRUE(Open(storage_key1_, "foo")); - base::WeakPtr<LegacyCacheStorageCache> cache = - LegacyCacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); + base::WeakPtr<CacheStorageCache> cache = + CacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); // Run a cache operation to ensure that the cache has finished initializing so // that when the handle is dropped it could possibly close immediately. EXPECT_FALSE(CacheMatch(callback_cache_handle_.value(), @@ -1202,8 +1201,8 @@ CacheStorageHandle cache_storage = CacheStorageForKey(storage_key1_); EXPECT_TRUE(Open(storage_key1_, "foo")); - base::WeakPtr<LegacyCacheStorageCache> cache = - LegacyCacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); + base::WeakPtr<CacheStorageCache> cache = + CacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); // Run a cache operation to ensure that the cache has finished initializing so // that when the handle is dropped it could possibly close immediately. EXPECT_FALSE(CacheMatch(callback_cache_handle_.value(), @@ -1229,8 +1228,8 @@ CacheStorageHandle cache_storage = CacheStorageForKey(storage_key1_); EXPECT_TRUE(Open(storage_key1_, "foo")); - base::WeakPtr<LegacyCacheStorageCache> cache = - LegacyCacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); + base::WeakPtr<CacheStorageCache> cache = + CacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); // Run a cache operation to ensure that the cache has finished initializing so // that when the handle is dropped it could possibly close immediately. EXPECT_FALSE(CacheMatch(callback_cache_handle_.value(), @@ -1262,8 +1261,8 @@ // Setup the cache and execute an operation to make sure all initialization // is complete. EXPECT_TRUE(Open(storage_key1_, "foo")); - base::WeakPtr<LegacyCacheStorageCache> cache = - LegacyCacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); + base::WeakPtr<CacheStorageCache> cache = + CacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); EXPECT_FALSE(CacheMatch(callback_cache_handle_.value(), GURL("http://example.com/foo"))); @@ -1375,9 +1374,8 @@ CacheStorageHandle cache_storage = CacheStorageForKey(storage_key1_); auto cache_handle = - LegacyCacheStorage::From(cache_storage)->GetLoadedCache(kCacheName); - base::FilePath cache_path = - LegacyCacheStorageCache::From(cache_handle)->path(); + CacheStorage::From(cache_storage)->GetLoadedCache(kCacheName); + base::FilePath cache_path = CacheStorageCache::From(cache_handle)->path(); base::FilePath storage_path = cache_path.DirName(); base::FilePath index_path = cache_path.AppendASCII("index"); cache_handle = CacheStorageCacheHandle(); @@ -1402,7 +1400,7 @@ // cache_storage index to have a much older time to ensure that it is not used // in the following Size() call. base::FilePath cache_index_path = - storage_path.AppendASCII(LegacyCacheStorage::kIndexFileName); + storage_path.AppendASCII(CacheStorage::kIndexFileName); base::Time t = base::Time::Now() + base::Hours(-1); EXPECT_TRUE(base::TouchFile(cache_index_path, t, t)); EXPECT_FALSE(IsIndexFileCurrent(storage_path)); @@ -1450,7 +1448,7 @@ CachePut(original_handle.value(), kFooURL, FetchResponseType::kOpaque)); int64_t cache_size_before_close = Size(storage_key1_); base::FilePath storage_dir = - LegacyCacheStorageCache::From(original_handle)->path().DirName(); + CacheStorageCache::From(original_handle)->path().DirName(); original_handle = CacheStorageCacheHandle(); EXPECT_GT(cache_size_before_close, 0); @@ -1522,8 +1520,8 @@ // calls delete. TEST_F(CacheStorageManagerMemoryOnlyTest, MemoryLosesReferenceOnlyAfterDelete) { EXPECT_TRUE(Open(storage_key1_, "foo")); - base::WeakPtr<LegacyCacheStorageCache> cache = - LegacyCacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); + base::WeakPtr<CacheStorageCache> cache = + CacheStorageCache::From(callback_cache_handle_)->AsWeakPtr(); callback_cache_handle_ = CacheStorageCacheHandle(); EXPECT_TRUE(cache); EXPECT_TRUE(Delete(storage_key1_, "foo")); @@ -1540,7 +1538,7 @@ TEST_P(CacheStorageManagerTestP, OpenRunsSerially) { EXPECT_FALSE(Delete(storage_key1_, "tmp")); // Init storage. CacheStorageHandle cache_storage = CacheStorageForKey(storage_key1_); - auto* impl = LegacyCacheStorage::From(cache_storage); + auto* impl = CacheStorage::From(cache_storage); auto id = impl->StartAsyncOperationForTesting(); base::RunLoop open_loop; @@ -1616,7 +1614,7 @@ EXPECT_TRUE(Open(storage_key1_, "foo")); base::FilePath storage_dir = - LegacyCacheStorageCache::From(callback_cache_handle_)->path().DirName(); + CacheStorageCache::From(callback_cache_handle_)->path().DirName(); base::FilePath index_path = storage_dir.AppendASCII("index.txt"); EXPECT_TRUE( CachePut(callback_cache_handle_.value(), GURL("http://example.com/foo"))); @@ -1714,7 +1712,7 @@ EXPECT_TRUE(CachePut(original_handle.value(), kFooURL)); int64_t cache_size_v1 = Size(storage_key1_); base::FilePath storage_dir = - LegacyCacheStorageCache::From(original_handle)->path().DirName(); + CacheStorageCache::From(original_handle)->path().DirName(); original_handle = CacheStorageCacheHandle(); EXPECT_GE(cache_size_v1, 0); @@ -1791,7 +1789,7 @@ EXPECT_TRUE(CachePut(original_handle.value(), kFooURL)); int64_t cache_size_v1 = Size(storage_key1_); base::FilePath storage_dir = - LegacyCacheStorageCache::From(original_handle)->path().DirName(); + CacheStorageCache::From(original_handle)->path().DirName(); original_handle = CacheStorageCacheHandle(); EXPECT_GE(cache_size_v1, 0); @@ -1903,11 +1901,10 @@ // Create an unreferenced directory next to the referenced one. auto* legacy_manager = - static_cast<LegacyCacheStorageManager*>(cache_manager_.get()); - base::FilePath origin_path = - LegacyCacheStorageManager::ConstructStorageKeyPath( - legacy_manager->root_path(), storage_key1_, - storage::mojom::CacheStorageOwner::kCacheAPI); + static_cast<CacheStorageManager*>(cache_manager_.get()); + base::FilePath origin_path = CacheStorageManager::ConstructStorageKeyPath( + legacy_manager->root_path(), storage_key1_, + storage::mojom::CacheStorageOwner::kCacheAPI); base::FilePath unreferenced_path = origin_path.AppendASCII("bar"); EXPECT_TRUE(CreateDirectory(unreferenced_path)); EXPECT_TRUE(base::DirectoryExists(unreferenced_path)); @@ -2503,7 +2500,7 @@ // Close the cache backend so that it writes out its index to disk. base::RunLoop run_loop; - LegacyCacheStorageCache::From(callback_cache_handle_) + CacheStorageCache::From(callback_cache_handle_) ->Close(run_loop.QuitClosure()); run_loop.Run(); @@ -2519,12 +2516,10 @@ TEST_F(CacheStorageManagerTest, UpgradePaddingVersion) { // Create an empty directory for the cache_storage files. auto* legacy_manager = - static_cast<LegacyCacheStorageManager*>(cache_manager_.get()); + static_cast<CacheStorageManager*>(cache_manager_.get()); base::FilePath manager_dir = legacy_manager->root_path(); - base::FilePath storage_dir = - LegacyCacheStorageManager::ConstructStorageKeyPath( - manager_dir, storage_key1_, - storage::mojom::CacheStorageOwner::kCacheAPI); + base::FilePath storage_dir = CacheStorageManager::ConstructStorageKeyPath( + manager_dir, storage_key1_, storage::mojom::CacheStorageOwner::kCacheAPI); EXPECT_TRUE(base::CreateDirectory(manager_dir)); // Destroy the manager while we operate on the underlying files.
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.cc b/content/browser/cache_storage/legacy/legacy_cache_storage.cc deleted file mode 100644 index 41bc265..0000000 --- a/content/browser/cache_storage/legacy/legacy_cache_storage.cc +++ /dev/null
@@ -1,1474 +0,0 @@ -// Copyright 2014 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 "content/browser/cache_storage/legacy/legacy_cache_storage.h" - -#include <stddef.h> - -#include <memory> -#include <set> -#include <string> -#include <utility> -#include <vector> - -#include "base/barrier_closure.h" -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/containers/contains.h" -#include "base/files/file_util.h" -#include "base/files/memory_mapped_file.h" -#include "base/guid.h" -#include "base/hash/sha1.h" -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_refptr.h" -#include "base/metrics/histogram_macros.h" -#include "base/numerics/safe_conversions.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/task/sequenced_task_runner.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/traced_value.h" -#include "build/build_config.h" -#include "content/browser/cache_storage/cache_storage.pb.h" -#include "content/browser/cache_storage/cache_storage_cache.h" -#include "content/browser/cache_storage/cache_storage_cache_handle.h" -#include "content/browser/cache_storage/cache_storage_histogram_utils.h" -#include "content/browser/cache_storage/cache_storage_index.h" -#include "content/browser/cache_storage/cache_storage_quota_client.h" -#include "content/browser/cache_storage/cache_storage_scheduler.h" -#include "content/browser/cache_storage/cache_storage_trace_utils.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h" -#include "content/common/background_fetch/background_fetch_types.h" -#include "crypto/symmetric_key.h" -#include "net/base/directory_lister.h" -#include "net/base/net_errors.h" -#include "storage/browser/blob/blob_storage_context.h" -#include "storage/browser/quota/quota_manager_proxy.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" -#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" - -using blink::mojom::CacheStorageError; -using blink::mojom::StorageType; -using crypto::SymmetricKey; - -namespace content { - -namespace { - -std::string HexedHash(const std::string& value) { - std::string value_hash = base::SHA1HashString(value); - std::string valued_hexed_hash = base::ToLowerASCII( - base::HexEncode(value_hash.c_str(), value_hash.length())); - return valued_hexed_hash; -} - -void SizeRetrievedFromAllCaches(std::unique_ptr<int64_t> accumulator, - LegacyCacheStorage::SizeCallback callback) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), *accumulator)); -} - -} // namespace - -const char LegacyCacheStorage::kIndexFileName[] = "index.txt"; - -struct LegacyCacheStorage::CacheMatchResponse { - CacheMatchResponse() = default; - ~CacheMatchResponse() = default; - - CacheStorageError error; - blink::mojom::FetchAPIResponsePtr response; -}; - -// Handles the loading and clean up of CacheStorageCache objects. -class LegacyCacheStorage::CacheLoader { - public: - using CacheAndErrorCallback = - base::OnceCallback<void(std::unique_ptr<LegacyCacheStorageCache>, - CacheStorageError status)>; - using BoolCallback = base::OnceCallback<void(bool)>; - using CacheStorageIndexLoadCallback = - base::OnceCallback<void(std::unique_ptr<CacheStorageIndex>)>; - - CacheLoader(base::SequencedTaskRunner* cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - LegacyCacheStorage* cache_storage, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) - : cache_task_runner_(cache_task_runner), - scheduler_task_runner_(std::move(scheduler_task_runner)), - quota_manager_proxy_(std::move(quota_manager_proxy)), - blob_storage_context_(std::move(blob_storage_context)), - cache_storage_(cache_storage), - storage_key_(storage_key), - owner_(owner) { - DCHECK(!storage_key_.origin().opaque()); - } - - virtual ~CacheLoader() {} - - // Creates a CacheStorageCache with the given name. It does not attempt to - // load the backend, that happens lazily when the cache is used. - virtual std::unique_ptr<LegacyCacheStorageCache> CreateCache( - const std::string& cache_name, - int64_t cache_size, - int64_t cache_padding) = 0; - - // Deletes any pre-existing cache of the same name and then loads it. - virtual void PrepareNewCacheDestination(const std::string& cache_name, - CacheAndErrorCallback callback) = 0; - - // After the backend has been deleted, do any extra house keeping such as - // removing the cache's directory. - virtual void CleanUpDeletedCache(CacheStorageCache* cache) = 0; - - // Writes the cache index to disk if applicable. - virtual void WriteIndex(const CacheStorageIndex& index, - BoolCallback callback) = 0; - - // Loads the cache index from disk if applicable. - virtual void LoadIndex(CacheStorageIndexLoadCallback callback) = 0; - - // Called when CacheStorage has created a cache. Used to hold onto a handle to - // the cache if necessary. - virtual void NotifyCacheCreated(const std::string& cache_name, - CacheStorageCacheHandle cache_handle) {} - - // Notification that the cache for |cache_handle| has been doomed. If the - // loader is holding a handle to the cache, it should drop it now. - virtual void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) {} - - protected: - const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; - const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; - - // Owned by CacheStorage which owns this. This is guaranteed to outlive - // CacheLoader, but we store a reference to keep it alive for callbacks. - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; - - scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; - - // Raw pointer is safe because this object is owned by cache_storage_. - raw_ptr<LegacyCacheStorage> cache_storage_; - - blink::StorageKey storage_key_; - storage::mojom::CacheStorageOwner owner_; -}; - -// Creates memory-only ServiceWorkerCaches. Because these caches have no -// persistent storage it is not safe to free them from memory if they might be -// used again. Therefore this class holds a reference to each cache until the -// cache is doomed. -class LegacyCacheStorage::MemoryLoader - : public LegacyCacheStorage::CacheLoader { - public: - MemoryLoader(base::SequencedTaskRunner* cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - LegacyCacheStorage* cache_storage, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) - : CacheLoader(cache_task_runner, - std::move(scheduler_task_runner), - std::move(quota_manager_proxy), - std::move(blob_storage_context), - cache_storage, - storage_key, - owner) {} - - std::unique_ptr<LegacyCacheStorageCache> CreateCache( - const std::string& cache_name, - int64_t cache_size, - int64_t cache_padding) override { - return LegacyCacheStorageCache::CreateMemoryCache( - storage_key_, owner_, cache_name, cache_storage_, - scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_); - } - - void PrepareNewCacheDestination(const std::string& cache_name, - CacheAndErrorCallback callback) override { - std::unique_ptr<LegacyCacheStorageCache> cache = - CreateCache(cache_name, /*cache_size=*/0, /*cache_padding=*/0); - std::move(callback).Run(std::move(cache), CacheStorageError::kSuccess); - } - - void CleanUpDeletedCache(CacheStorageCache* cache) override {} - - void WriteIndex(const CacheStorageIndex& index, - BoolCallback callback) override { - std::move(callback).Run(true); - } - - void LoadIndex(CacheStorageIndexLoadCallback callback) override { - std::move(callback).Run(std::make_unique<CacheStorageIndex>()); - } - - void NotifyCacheCreated(const std::string& cache_name, - CacheStorageCacheHandle cache_handle) override { - DCHECK(!base::Contains(cache_handles_, cache_name)); - cache_handles_.insert(std::make_pair(cache_name, std::move(cache_handle))); - } - - void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override { - auto* impl = LegacyCacheStorageCache::From(cache_handle); - DCHECK(base::Contains(cache_handles_, impl->cache_name())); - cache_handles_.erase(impl->cache_name()); - } - - private: - typedef std::map<std::string, CacheStorageCacheHandle> CacheHandles; - ~MemoryLoader() override {} - - // Keep a reference to each cache to ensure that it's not freed before the - // client calls LegacyCacheStorage::Delete or the CacheStorage is - // freed. - CacheHandles cache_handles_; -}; - -class LegacyCacheStorage::SimpleCacheLoader - : public LegacyCacheStorage::CacheLoader { - public: - SimpleCacheLoader( - const base::FilePath& origin_path, - base::SequencedTaskRunner* cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - LegacyCacheStorage* cache_storage, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) - : CacheLoader(cache_task_runner, - std::move(scheduler_task_runner), - std::move(quota_manager_proxy), - std::move(blob_storage_context), - cache_storage, - storage_key, - owner), - origin_path_(origin_path) {} - - std::unique_ptr<LegacyCacheStorageCache> CreateCache( - const std::string& cache_name, - int64_t cache_size, - int64_t cache_padding) override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(base::Contains(cache_name_to_cache_dir_, cache_name)); - - std::string cache_dir = cache_name_to_cache_dir_[cache_name]; - base::FilePath cache_path = origin_path_.AppendASCII(cache_dir); - return LegacyCacheStorageCache::CreatePersistentCache( - storage_key_, owner_, cache_name, cache_storage_, cache_path, - scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_, - cache_size, cache_padding); - } - - void PrepareNewCacheDestination(const std::string& cache_name, - CacheAndErrorCallback callback) override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - PostTaskAndReplyWithResult( - cache_task_runner_.get(), FROM_HERE, - base::BindOnce(&SimpleCacheLoader::PrepareNewCacheDirectoryInPool, - origin_path_), - base::BindOnce(&SimpleCacheLoader::PrepareNewCacheCreateCache, - weak_ptr_factory_.GetWeakPtr(), cache_name, - std::move(callback))); - } - - // Runs on the cache_task_runner_. - static std::tuple<CacheStorageError, std::string> - PrepareNewCacheDirectoryInPool(const base::FilePath& origin_path) { - std::string cache_dir; - base::FilePath cache_path; - do { - cache_dir = base::GenerateGUID(); - cache_path = origin_path.AppendASCII(cache_dir); - } while (base::PathExists(cache_path)); - - base::File::Error error = base::File::FILE_OK; - if (base::CreateDirectoryAndGetError(cache_path, &error)) { - return std::make_tuple(CacheStorageError::kSuccess, cache_dir); - } else { - CacheStorageError status = - error == base::File::FILE_ERROR_NO_SPACE - ? CacheStorageError::kErrorQuotaExceeded - : MakeErrorStorage(ErrorStorageType::kDidCreateNullCache); - return std::make_tuple(status, cache_dir); - } - } - - void PrepareNewCacheCreateCache( - const std::string& cache_name, - CacheAndErrorCallback callback, - const std::tuple<CacheStorageError, std::string>& result) { - CacheStorageError status = std::get<0>(result); - const std::string& cache_dir = std::get<1>(result); - - if (status != CacheStorageError::kSuccess) { - std::move(callback).Run(nullptr, status); - return; - } - DCHECK(!cache_dir.empty()); - - cache_name_to_cache_dir_[cache_name] = cache_dir; - std::move(callback).Run( - CreateCache(cache_name, LegacyCacheStorage::kSizeUnknown, - LegacyCacheStorage::kSizeUnknown), - CacheStorageError::kSuccess); - } - - void CleanUpDeletedCache(CacheStorageCache* cache) override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(base::Contains(doomed_cache_to_path_, cache)); - - base::FilePath cache_path = - origin_path_.AppendASCII(doomed_cache_to_path_[cache]); - doomed_cache_to_path_.erase(cache); - - cache_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool, - cache_path)); - } - - static void CleanUpDeleteCacheDirInPool(const base::FilePath& cache_path) { - base::DeletePathRecursively(cache_path); - } - - void WriteIndex(const CacheStorageIndex& index, - BoolCallback callback) override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // 1. Create the index file as a string. (WriteIndex) - // 2. Write the file to disk. (WriteIndexWriteToFileInPool) - - proto::CacheStorageIndex protobuf_index; - // GetURL().spec() is used here rather than Serialize() to ensure - // backwards compatibility with older data. The serializations are - // subtly different, e.g. Origin does not include a trailing "/". - // TODO(crbug.com/809329): Add a test for validating fields in the proto - // - // TODO(https://crbug.com/1199077): We need to serialize the entire - // `storage_key_` into the index file. - protobuf_index.set_origin(storage_key_.origin().GetURL().spec()); - - for (const auto& cache_metadata : index.ordered_cache_metadata()) { - DCHECK(base::Contains(cache_name_to_cache_dir_, cache_metadata.name)); - - proto::CacheStorageIndex::Cache* index_cache = protobuf_index.add_cache(); - index_cache->set_name(cache_metadata.name); - index_cache->set_cache_dir(cache_name_to_cache_dir_[cache_metadata.name]); - if (cache_metadata.size == LegacyCacheStorage::kSizeUnknown) - index_cache->clear_size(); - else - index_cache->set_size(cache_metadata.size); - index_cache->set_padding(cache_metadata.padding); - index_cache->set_padding_version( - LegacyCacheStorageCache::GetResponsePaddingVersion()); - } - - std::string serialized; - bool success = protobuf_index.SerializeToString(&serialized); - DCHECK(success); - - base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp"); - base::FilePath index_path = - origin_path_.AppendASCII(LegacyCacheStorage::kIndexFileName); - - PostTaskAndReplyWithResult( - cache_task_runner_.get(), FROM_HERE, - base::BindOnce(&SimpleCacheLoader::WriteIndexWriteToFileInPool, - tmp_path, index_path, serialized, quota_manager_proxy_, - storage_key_), - std::move(callback)); - } - - static bool WriteIndexWriteToFileInPool( - const base::FilePath& tmp_path, - const base::FilePath& index_path, - const std::string& data, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - const blink::StorageKey& storage_key) { - int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size()); - if (bytes_written != base::checked_cast<int>(data.size())) { - base::DeleteFile(tmp_path); - quota_manager_proxy->NotifyWriteFailed(storage_key); - return false; - } - - // Atomically rename the temporary index file to become the real one. - return base::ReplaceFile(tmp_path, index_path, nullptr); - } - - void LoadIndex(CacheStorageIndexLoadCallback callback) override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - PostTaskAndReplyWithResult( - cache_task_runner_.get(), FROM_HERE, - base::BindOnce(&SimpleCacheLoader::ReadAndMigrateIndexInPool, - origin_path_, quota_manager_proxy_, storage_key_), - base::BindOnce(&SimpleCacheLoader::LoadIndexDidReadIndex, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); - } - - void LoadIndexDidReadIndex(CacheStorageIndexLoadCallback callback, - proto::CacheStorageIndex protobuf_index) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::unique_ptr<std::set<std::string>> cache_dirs( - new std::set<std::string>); - - auto index = std::make_unique<CacheStorageIndex>(); - for (int i = 0, max = protobuf_index.cache_size(); i < max; ++i) { - const proto::CacheStorageIndex::Cache& cache = protobuf_index.cache(i); - DCHECK(cache.has_cache_dir()); - int64_t cache_size = - cache.has_size() ? cache.size() : LegacyCacheStorage::kSizeUnknown; - int64_t cache_padding; - if (cache.has_padding()) { - if (cache.has_padding_version() && - cache.padding_version() == - LegacyCacheStorageCache::GetResponsePaddingVersion()) { - cache_padding = cache.padding(); - } else { - // The padding algorithm version changed so set to unknown to force - // recalculation. - cache_padding = LegacyCacheStorage::kSizeUnknown; - } - } else { - cache_padding = LegacyCacheStorage::kSizeUnknown; - } - - index->Insert(CacheStorageIndex::CacheMetadata(cache.name(), cache_size, - cache_padding)); - cache_name_to_cache_dir_[cache.name()] = cache.cache_dir(); - cache_dirs->insert(cache.cache_dir()); - } - - cache_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&DeleteUnreferencedCachesInPool, origin_path_, - std::move(cache_dirs))); - std::move(callback).Run(std::move(index)); - } - - void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override { - auto* impl = LegacyCacheStorageCache::From(cache_handle); - DCHECK(base::Contains(cache_name_to_cache_dir_, impl->cache_name())); - auto iter = cache_name_to_cache_dir_.find(impl->cache_name()); - doomed_cache_to_path_[cache_handle.value()] = iter->second; - cache_name_to_cache_dir_.erase(iter); - } - - private: - friend class MigratedLegacyCacheDirectoryNameTest; - ~SimpleCacheLoader() override {} - - // Iterates over the caches and deletes any directory not found in - // |cache_dirs|. Runs on cache_task_runner_ - static void DeleteUnreferencedCachesInPool( - const base::FilePath& cache_base_dir, - std::unique_ptr<std::set<std::string>> cache_dirs) { - base::FileEnumerator file_enum(cache_base_dir, false /* recursive */, - base::FileEnumerator::DIRECTORIES); - std::vector<base::FilePath> dirs_to_delete; - { - base::FilePath cache_path; - while (!(cache_path = file_enum.Next()).empty()) { - if (!base::Contains(*cache_dirs, cache_path.BaseName().AsUTF8Unsafe())) - dirs_to_delete.push_back(cache_path); - } - } - - for (const base::FilePath& cache_path : dirs_to_delete) - base::DeletePathRecursively(cache_path); - } - - // Runs on cache_task_runner_ - static proto::CacheStorageIndex ReadAndMigrateIndexInPool( - const base::FilePath& origin_path, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - const blink::StorageKey& storage_key) { - const base::FilePath index_path = - origin_path.AppendASCII(LegacyCacheStorage::kIndexFileName); - - proto::CacheStorageIndex index; - std::string body; - if (!base::ReadFileToString(index_path, &body) || - !index.ParseFromString(body)) - return proto::CacheStorageIndex(); - body.clear(); - - base::File::Info file_info; - base::Time index_last_modified; - if (GetFileInfo(index_path, &file_info)) - index_last_modified = file_info.last_modified; - bool index_modified = false; - - // Look for caches that have no cache_dir. Give any such caches a directory - // with a random name and move them there. Then, rewrite the index file. - // Additionally invalidate the size of any index entries where the cache was - // modified after the index (making it out-of-date). - for (int i = 0, max = index.cache_size(); i < max; ++i) { - const proto::CacheStorageIndex::Cache& cache = index.cache(i); - if (cache.has_cache_dir()) { - if (cache.has_size()) { - base::FilePath cache_dir = origin_path.AppendASCII(cache.cache_dir()); - if (!GetFileInfo(cache_dir, &file_info) || - index_last_modified <= file_info.last_modified) { - // Index is older than this cache, so invalidate index entries that - // may change as a result of cache operations. - index.mutable_cache(i)->clear_size(); - } - } - } else { - // Find a new home for the cache. - base::FilePath legacy_cache_path = - origin_path.AppendASCII(HexedHash(cache.name())); - std::string cache_dir; - base::FilePath cache_path; - do { - cache_dir = base::GenerateGUID(); - cache_path = origin_path.AppendASCII(cache_dir); - } while (base::PathExists(cache_path)); - - if (!base::Move(legacy_cache_path, cache_path)) { - // If the move fails then the cache is in a bad state. Return an empty - // index so that the CacheStorage can start fresh. The unreferenced - // caches will be discarded later in initialization. - return proto::CacheStorageIndex(); - } - - index.mutable_cache(i)->set_cache_dir(cache_dir); - index.mutable_cache(i)->clear_size(); - index_modified = true; - } - } - - if (index_modified) { - base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp"); - if (!index.SerializeToString(&body) || - !WriteIndexWriteToFileInPool(tmp_path, index_path, body, - std::move(quota_manager_proxy), - storage_key)) { - return proto::CacheStorageIndex(); - } - } - - return index; - } - - const base::FilePath origin_path_; - std::map<std::string, std::string> cache_name_to_cache_dir_; - std::map<CacheStorageCache*, std::string> doomed_cache_to_path_; - - SEQUENCE_CHECKER(sequence_checker_); - base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_{this}; -}; - -LegacyCacheStorage::LegacyCacheStorage( - const base::FilePath& path, - bool memory_only, - base::SequencedTaskRunner* cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - LegacyCacheStorageManager* cache_storage_manager, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) - : CacheStorage(storage_key), - initialized_(false), - initializing_(false), - memory_only_(memory_only), - scheduler_( - new CacheStorageScheduler(CacheStorageSchedulerClient::kStorage, - scheduler_task_runner)), - origin_path_(path), - cache_task_runner_(cache_task_runner), - quota_manager_proxy_(quota_manager_proxy), - blob_storage_context_(std::move(blob_storage_context)), - owner_(owner), - cache_storage_manager_(cache_storage_manager) { - if (memory_only) { - cache_loader_ = base::WrapUnique<CacheLoader>(new MemoryLoader( - cache_task_runner_.get(), std::move(scheduler_task_runner), - quota_manager_proxy, blob_storage_context_, this, storage_key, owner)); - return; - } - - cache_loader_ = base::WrapUnique<CacheLoader>(new SimpleCacheLoader( - origin_path_, cache_task_runner_.get(), std::move(scheduler_task_runner), - quota_manager_proxy, blob_storage_context_, this, storage_key, owner)); - -#if BUILDFLAG(IS_ANDROID) - app_status_listener_ = base::android::ApplicationStatusListener::New( - base::BindRepeating(&LegacyCacheStorage::OnApplicationStateChange, - weak_factory_.GetWeakPtr())); -#endif -} - -LegacyCacheStorage::~LegacyCacheStorage() { - FlushIndexIfDirty(); -} - -CacheStorageHandle LegacyCacheStorage::CreateHandle() { - return CacheStorageHandle(weak_factory_.GetWeakPtr()); -} - -void LegacyCacheStorage::AddHandleRef() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - handle_ref_count_ += 1; -} - -void LegacyCacheStorage::DropHandleRef() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK_GT(handle_ref_count_, 0U); - handle_ref_count_ -= 1; - if (!handle_ref_count_ && cache_storage_manager_) { - ReleaseUnreferencedCaches(); - cache_storage_manager_->CacheStorageUnreferenced(this, storage_key_, - owner_); - } -} - -void LegacyCacheStorage::Init() { - if (!initialized_) - LazyInit(); -} - -void LegacyCacheStorage::OpenCache(const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - // TODO: Hold a handle to this CacheStorage instance while executing - // operations to better support use by internal code that may - // start a single operation without explicitly maintaining a - // handle. - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kOpen, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::OpenCacheImpl, weak_factory_.GetWeakPtr(), - cache_name, trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::HasCache(const std::string& cache_name, - int64_t trace_id, - BoolAndErrorCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kHas, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::HasCacheImpl, weak_factory_.GetWeakPtr(), - cache_name, trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::DoomCache(const std::string& cache_name, - int64_t trace_id, - ErrorCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kExclusive, - CacheStorageSchedulerOp::kDelete, CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::DoomCacheImpl, weak_factory_.GetWeakPtr(), - cache_name, trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::EnumerateCaches(int64_t trace_id, - EnumerateCachesCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::EnumerateCachesImpl, weak_factory_.GetWeakPtr(), - trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::MatchCache( - const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(), - cache_name, std::move(request), std::move(match_options), priority, - trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::MatchAllCaches( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, - CacheStorageSchedulerOp::kMatchAll, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::MatchAllCachesImpl, weak_factory_.GetWeakPtr(), - std::move(request), std::move(match_options), priority, trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::WriteToCache( - const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - LegacyCacheStorage::ErrorCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - quota_manager_proxy_->NotifyStorageAccessed( - storage_key_, StorageType::kTemporary, base::Time::Now()); - - // Note, this is a shared operation since it only reads CacheStorage data. - // The CacheStorageCache is responsible for making its put operation - // exclusive. - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kPut, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::WriteToCacheImpl, weak_factory_.GetWeakPtr(), - cache_name, std::move(request), std::move(response), trace_id, - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::GetSizeThenCloseAllCaches(SizeCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - // Note, this is a shared operation since it only reads CacheStorage data. - // The CacheStorageCache is responsible for making its close operation - // exclusive. - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, - CacheStorageSchedulerOp::kSizeThenClose, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::GetSizeThenCloseAllCachesImpl, - weak_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::Size(LegacyCacheStorage::SizeCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!initialized_) - LazyInit(); - - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::SizeImpl, weak_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::ResetManager() { - cache_storage_manager_ = nullptr; -} - -void LegacyCacheStorage::NotifyCacheContentChanged( - const std::string& cache_name) { - if (cache_storage_manager_) - cache_storage_manager_->NotifyCacheContentChanged(storage_key_, cache_name); -} - -void LegacyCacheStorage::ScheduleWriteIndex() { - // These values are chosen to be equal or greater than the simple disk_cache - // index write delays. We want the cache_storage index to be written last. - static const int64_t kWriteIndexDelayMilliseconds = 20050; - static const int64_t kWriteIndexBackgroundDelayMilliseconds = 150; - int64_t delay_ms = app_on_background_ ? kWriteIndexBackgroundDelayMilliseconds - : kWriteIndexDelayMilliseconds; - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - index_write_task_.Reset(base::BindOnce(&LegacyCacheStorage::WriteIndex, - weak_factory_.GetWeakPtr(), - base::DoNothing())); - base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, index_write_task_.callback(), base::Milliseconds(delay_ms)); -} - -void LegacyCacheStorage::WriteIndex(base::OnceCallback<void(bool)> callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kExclusive, - CacheStorageSchedulerOp::kWriteIndex, - CacheStorageSchedulerPriority::kNormal, - base::BindOnce( - &LegacyCacheStorage::WriteIndexImpl, weak_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); -} - -void LegacyCacheStorage::WriteIndexImpl( - base::OnceCallback<void(bool)> callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(scheduler_->IsRunningExclusiveOperation()); - cache_loader_->WriteIndex(*cache_index_, std::move(callback)); -} - -bool LegacyCacheStorage::InitiateScheduledIndexWriteForTest( - base::OnceCallback<void(bool)> callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (index_write_pending()) { - index_write_task_.Cancel(); - WriteIndex(std::move(callback)); - return true; - } - std::move(callback).Run(true /* success */); - return false; -} - -void LegacyCacheStorage::CacheSizeUpdated( - const LegacyCacheStorageCache* cache) { - // Should not be called for doomed caches. - DCHECK(!base::Contains(doomed_caches_, - const_cast<LegacyCacheStorageCache*>(cache))); - DCHECK_NE(cache->cache_padding(), kSizeUnknown); - bool size_changed = - cache_index_->SetCacheSize(cache->cache_name(), cache->cache_size()); - bool padding_changed = cache_index_->SetCachePadding(cache->cache_name(), - cache->cache_padding()); - if (size_changed || padding_changed) - ScheduleWriteIndex(); -} - -void LegacyCacheStorage::ReleaseUnreferencedCaches() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - for (auto& entry : cache_map_) { - if (entry.second && entry.second->IsUnreferenced()) - entry.second.reset(); - } -} - -void LegacyCacheStorage::CacheUnreferenced(LegacyCacheStorageCache* cache) { - DCHECK(cache); - DCHECK(cache->IsUnreferenced()); - auto doomed_caches_it = doomed_caches_.find(cache); - if (doomed_caches_it != doomed_caches_.end()) { - // The last reference to a doomed cache is gone, perform clean up. - DeleteCacheFinalize(cache); - return; - } - - // Opportunistically keep warmed caches open when the CacheStorage is - // still actively referenced. Repeatedly opening and closing simple - // disk_cache backends can be quite slow. This is easy to trigger when - // a site uses caches.match() frequently because the a Cache object is - // never exposed to script to explicitly hold the backend open. - if (handle_ref_count_) - return; - - // The CacheStorage is not actively being referenced. Close the cache - // immediately. - auto cache_map_it = cache_map_.find(cache->cache_name()); - DCHECK(cache_map_it != cache_map_.end()); - - cache_map_it->second.reset(); -} - -CacheStorageSchedulerId LegacyCacheStorage::StartAsyncOperationForTesting() { - auto id = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, - CacheStorageSchedulerPriority::kNormal, base::DoNothing()); - return id; -} - -void LegacyCacheStorage::CompleteAsyncOperationForTesting( - CacheStorageSchedulerId id) { - scheduler_->CompleteOperationAndRunNext(id); -} - -// Init is run lazily so that it is called on the proper MessageLoop. -void LegacyCacheStorage::LazyInit() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!initialized_); - - if (initializing_) - return; - - DCHECK(!scheduler_->ScheduledOperations()); - - initializing_ = true; - init_id_ = scheduler_->CreateId(); - scheduler_->ScheduleOperation( - init_id_, CacheStorageSchedulerMode::kExclusive, - CacheStorageSchedulerOp::kInit, CacheStorageSchedulerPriority::kNormal, - base::BindOnce(&LegacyCacheStorage::LazyInitImpl, - weak_factory_.GetWeakPtr())); -} - -void LegacyCacheStorage::LazyInitImpl() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!initialized_); - DCHECK(initializing_); - - // 1. Get the cache index (async call) - // 2. For each cache name, load the cache (async call) - // 3. Once each load is complete, update the map variables. - // 4. Call the list of waiting callbacks. - - DCHECK(scheduler_->IsRunningExclusiveOperation()); - cache_loader_->LoadIndex(base::BindOnce( - &LegacyCacheStorage::LazyInitDidLoadIndex, weak_factory_.GetWeakPtr())); -} - -void LegacyCacheStorage::LazyInitDidLoadIndex( - std::unique_ptr<CacheStorageIndex> index) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(cache_map_.empty()); - - for (const auto& cache_metadata : index->ordered_cache_metadata()) { - cache_map_.insert(std::make_pair(cache_metadata.name, nullptr)); - } - - DCHECK(!cache_index_); - cache_index_ = std::move(index); - - initializing_ = false; - initialized_ = true; - - scheduler_->CompleteOperationAndRunNext(init_id_); -} - -void LegacyCacheStorage::OpenCacheImpl(const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback) { - TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::OpenCacheImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "cache_name", cache_name); - CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); - if (cache_handle.value()) { - std::move(callback).Run(std::move(cache_handle), - CacheStorageError::kSuccess); - return; - } - - DCHECK(scheduler_->IsRunningExclusiveOperation()); - cache_loader_->PrepareNewCacheDestination( - cache_name, base::BindOnce(&LegacyCacheStorage::CreateCacheDidCreateCache, - weak_factory_.GetWeakPtr(), cache_name, - trace_id, std::move(callback))); -} - -void LegacyCacheStorage::CreateCacheDidCreateCache( - const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback, - std::unique_ptr<LegacyCacheStorageCache> cache, - CacheStorageError status) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::CreateCacheDidCreateCache", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - - UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult", - static_cast<bool>(cache)); - - if (status != CacheStorageError::kSuccess) { - std::move(callback).Run(CacheStorageCacheHandle(), status); - return; - } - - LegacyCacheStorageCache* cache_ptr = cache.get(); - - cache_map_.insert(std::make_pair(cache_name, std::move(cache))); - cache_index_->Insert(CacheStorageIndex::CacheMetadata( - cache_name, cache_ptr->cache_size(), cache_ptr->cache_padding())); - - CacheStorageCacheHandle handle = cache_ptr->CreateHandle(); - index_write_task_.Cancel(); - cache_loader_->WriteIndex( - *cache_index_, - base::BindOnce(&LegacyCacheStorage::CreateCacheDidWriteIndex, - weak_factory_.GetWeakPtr(), std::move(callback), - cache_ptr->CreateHandle(), trace_id)); - - cache_loader_->NotifyCacheCreated(cache_name, std::move(handle)); - if (cache_storage_manager_) - cache_storage_manager_->NotifyCacheListChanged(storage_key_); -} - -void LegacyCacheStorage::CreateCacheDidWriteIndex( - CacheAndErrorCallback callback, - CacheStorageCacheHandle cache_handle, - int64_t trace_id, - bool success) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(cache_handle.value()); - - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::CreateCacheDidWriteIndex", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - - // TODO(jkarlin): Handle !success. - - std::move(callback).Run(std::move(cache_handle), CacheStorageError::kSuccess); -} - -void LegacyCacheStorage::HasCacheImpl(const std::string& cache_name, - int64_t trace_id, - BoolAndErrorCallback callback) { - TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::HasCacheImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "cache_name", cache_name); - bool has_cache = base::Contains(cache_map_, cache_name); - std::move(callback).Run(has_cache, CacheStorageError::kSuccess); -} - -void LegacyCacheStorage::DoomCacheImpl(const std::string& cache_name, - int64_t trace_id, - ErrorCallback callback) { - TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::DoomCacheImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "cache_name", cache_name); - CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); - if (!cache_handle.value()) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), CacheStorageError::kErrorNotFound)); - return; - } - - DCHECK(scheduler_->IsRunningExclusiveOperation()); - LegacyCacheStorageCache::From(cache_handle)->SetObserver(nullptr); - cache_index_->DoomCache(cache_name); - index_write_task_.Cancel(); - cache_loader_->WriteIndex( - *cache_index_, - base::BindOnce(&LegacyCacheStorage::DeleteCacheDidWriteIndex, - weak_factory_.GetWeakPtr(), std::move(cache_handle), - std::move(callback), trace_id)); -} - -void LegacyCacheStorage::DeleteCacheDidWriteIndex( - CacheStorageCacheHandle cache_handle, - ErrorCallback callback, - int64_t trace_id, - bool success) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto* impl = LegacyCacheStorageCache::From(cache_handle); - - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::DeleteCacheDidWriteIndex", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - - if (!success) { - // Undo any changes if the index couldn't be written to disk. - cache_index_->RestoreDoomedCache(); - impl->SetObserver(this); - std::move(callback).Run( - MakeErrorStorage(ErrorStorageType::kDeleteCacheFailed)); - return; - } - - cache_index_->FinalizeDoomedCache(); - - auto map_iter = cache_map_.find(impl->cache_name()); - DCHECK(map_iter != cache_map_.end()); - - doomed_caches_.insert( - std::make_pair(map_iter->second.get(), std::move(map_iter->second))); - cache_map_.erase(map_iter); - - cache_loader_->NotifyCacheDoomed(std::move(cache_handle)); - if (cache_storage_manager_) - cache_storage_manager_->NotifyCacheListChanged(storage_key_); - - std::move(callback).Run(CacheStorageError::kSuccess); -} - -// Call this once the last handle to a doomed cache is gone. It's okay if this -// doesn't get to complete before shutdown, the cache will be removed from disk -// on next startup in that case. -void LegacyCacheStorage::DeleteCacheFinalize( - LegacyCacheStorageCache* doomed_cache) { - doomed_cache->Size(base::BindOnce(&LegacyCacheStorage::DeleteCacheDidGetSize, - weak_factory_.GetWeakPtr(), doomed_cache)); -} - -void LegacyCacheStorage::DeleteCacheDidGetSize( - LegacyCacheStorageCache* doomed_cache, - int64_t cache_size) { - quota_manager_proxy_->NotifyStorageModified( - CacheStorageQuotaClient::GetClientTypeFromOwner(owner_), storage_key_, - StorageType::kTemporary, -cache_size, base::Time::Now(), - base::SequencedTaskRunnerHandle::Get(), base::DoNothing()); - - cache_loader_->CleanUpDeletedCache(doomed_cache); - auto doomed_caches_iter = doomed_caches_.find(doomed_cache); - DCHECK(doomed_caches_iter != doomed_caches_.end()); - doomed_caches_.erase(doomed_caches_iter); -} - -void LegacyCacheStorage::EnumerateCachesImpl(int64_t trace_id, - EnumerateCachesCallback callback) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::EnumerateCachesImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - - std::vector<std::string> list; - - for (const auto& metadata : cache_index_->ordered_cache_metadata()) { - list.push_back(metadata.name); - } - - std::move(callback).Run(std::move(list)); -} - -void LegacyCacheStorage::MatchCacheImpl( - const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) { - TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorage::MatchCacheImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "cache_name", cache_name, "request", - CacheStorageTracedValue(request)); - - CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); - - if (!cache_handle.value()) { - std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound, - nullptr); - return; - } - - // Pass the cache handle along to the callback to keep the cache open until - // match is done. - CacheStorageCache* cache_ptr = cache_handle.value(); - cache_ptr->Match( - std::move(request), std::move(match_options), priority, trace_id, - base::BindOnce(&LegacyCacheStorage::MatchCacheDidMatch, - weak_factory_.GetWeakPtr(), std::move(cache_handle), - trace_id, std::move(callback))); -} - -void LegacyCacheStorage::MatchCacheDidMatch( - CacheStorageCacheHandle cache_handle, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback, - CacheStorageError error, - blink::mojom::FetchAPIResponsePtr response) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::MatchCacheDidMatch", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - std::move(callback).Run(error, std::move(response)); -} - -void LegacyCacheStorage::MatchAllCachesImpl( - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::MatchAllCachesImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - - std::vector<CacheMatchResponse>* match_responses = - new std::vector<CacheMatchResponse>(cache_index_->num_entries()); - - base::RepeatingClosure barrier_closure = base::BarrierClosure( - cache_index_->num_entries(), - base::BindOnce(&LegacyCacheStorage::MatchAllCachesDidMatchAll, - weak_factory_.GetWeakPtr(), - base::WrapUnique(match_responses), trace_id, - std::move(callback))); - - size_t idx = 0; - for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) { - CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name); - DCHECK(cache_handle.value()); - - CacheStorageCache* cache_ptr = cache_handle.value(); - cache_ptr->Match( - BackgroundFetchSettledFetch::CloneRequest(request), - match_options ? match_options->Clone() : nullptr, priority, trace_id, - base::BindOnce(&LegacyCacheStorage::MatchAllCachesDidMatch, - weak_factory_.GetWeakPtr(), std::move(cache_handle), - &match_responses->at(idx), barrier_closure, trace_id)); - idx++; - } -} - -void LegacyCacheStorage::MatchAllCachesDidMatch( - CacheStorageCacheHandle cache_handle, - CacheMatchResponse* out_match_response, - const base::RepeatingClosure& barrier_closure, - int64_t trace_id, - CacheStorageError error, - blink::mojom::FetchAPIResponsePtr response) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::MatchAllCachesDidMatch", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - out_match_response->error = error; - out_match_response->response = std::move(response); - barrier_closure.Run(); -} - -void LegacyCacheStorage::MatchAllCachesDidMatchAll( - std::unique_ptr<std::vector<CacheMatchResponse>> match_responses, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) { - TRACE_EVENT_WITH_FLOW0("CacheStorage", - "LegacyCacheStorage::MatchAllCachesDidMatchAll", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - for (CacheMatchResponse& match_response : *match_responses) { - if (match_response.error == CacheStorageError::kErrorNotFound) - continue; - std::move(callback).Run(match_response.error, - std::move(match_response.response)); - return; - } - std::move(callback).Run(CacheStorageError::kErrorNotFound, nullptr); -} - -void LegacyCacheStorage::WriteToCacheImpl( - const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - LegacyCacheStorage::ErrorCallback callback) { - TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorage::WriteToCacheImpl", - TRACE_ID_GLOBAL(trace_id), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "cache_name", cache_name, "request", - CacheStorageTracedValue(request)); - - CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name); - - if (!cache_handle.value()) { - std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound); - return; - } - - CacheStorageCache* cache_ptr = cache_handle.value(); - DCHECK(cache_ptr); - - cache_ptr->Put(std::move(request), std::move(response), trace_id, - std::move(callback)); -} - -CacheStorageCacheHandle LegacyCacheStorage::GetLoadedCache( - const std::string& cache_name) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(initialized_); - - auto map_iter = cache_map_.find(cache_name); - if (map_iter == cache_map_.end()) - return CacheStorageCacheHandle(); - - CacheStorageCache* cache = map_iter->second.get(); - - if (!cache) { - const CacheStorageIndex::CacheMetadata* metadata = - cache_index_->GetMetadata(cache_name); - DCHECK(metadata); - std::unique_ptr<LegacyCacheStorageCache> new_cache = - cache_loader_->CreateCache(cache_name, metadata->size, - metadata->padding); - CacheStorageCache* cache_ptr = new_cache.get(); - map_iter->second = std::move(new_cache); - - return cache_ptr->CreateHandle(); - } - - return cache->CreateHandle(); -} - -void LegacyCacheStorage::SizeRetrievedFromCache( - CacheStorageCacheHandle cache_handle, - base::OnceClosure closure, - int64_t* accumulator, - int64_t size) { - auto* impl = LegacyCacheStorageCache::From(cache_handle); - if (doomed_caches_.find(impl) == doomed_caches_.end()) { - cache_index_->SetCacheSize(impl->cache_name(), impl->cache_size()); - cache_index_->SetCachePadding(impl->cache_name(), impl->cache_padding()); - } - *accumulator += (impl->cache_size() + impl->cache_padding()); - std::move(closure).Run(); -} - -void LegacyCacheStorage::GetSizeThenCloseAllCachesImpl(SizeCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(initialized_); - - std::unique_ptr<int64_t> accumulator(new int64_t(0)); - int64_t* accumulator_ptr = accumulator.get(); - - base::RepeatingClosure barrier_closure = base::BarrierClosure( - cache_index_->num_entries() + doomed_caches_.size(), - base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator), - std::move(callback))); - - for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) { - auto cache_handle = GetLoadedCache(cache_metadata.name); - LegacyCacheStorageCache* cache = - LegacyCacheStorageCache::From(cache_handle); - cache->GetSizeThenClose(base::BindOnce( - &LegacyCacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(), - std::move(cache_handle), barrier_closure, accumulator_ptr)); - } - - for (const auto& cache_it : doomed_caches_) { - LegacyCacheStorageCache* cache = cache_it.first; - cache->GetSizeThenClose(base::BindOnce( - &LegacyCacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(), - cache->CreateHandle(), barrier_closure, accumulator_ptr)); - } -} - -void LegacyCacheStorage::SizeImpl(SizeCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(initialized_); - - if (cache_index_->GetPaddedStorageSize() != kSizeUnknown) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), - cache_index_->GetPaddedStorageSize())); - return; - } - - std::unique_ptr<int64_t> accumulator(new int64_t(0)); - int64_t* accumulator_ptr = accumulator.get(); - - base::RepeatingClosure barrier_closure = base::BarrierClosure( - cache_index_->num_entries(), - base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator), - std::move(callback))); - - for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) { - if (cache_metadata.size != LegacyCacheStorage::kSizeUnknown && - cache_metadata.padding != LegacyCacheStorage::kSizeUnknown) { - *accumulator_ptr += (cache_metadata.size + cache_metadata.padding); - barrier_closure.Run(); - continue; - } - CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name); - LegacyCacheStorageCache* cache = - LegacyCacheStorageCache::From(cache_handle); - cache->Size(base::BindOnce( - &LegacyCacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(), - std::move(cache_handle), barrier_closure, accumulator_ptr)); - } -} - -void LegacyCacheStorage::FlushIndexIfDirty() { - if (!index_write_pending()) - return; - index_write_task_.Cancel(); - cache_loader_->WriteIndex(*cache_index_, base::DoNothing()); -} - -#if BUILDFLAG(IS_ANDROID) -void LegacyCacheStorage::OnApplicationStateChange( - base::android::ApplicationState state) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { - app_on_background_ = false; - } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) { - app_on_background_ = true; - FlushIndexIfDirty(); - } -} -#endif - -} // namespace content
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.h b/content/browser/cache_storage/legacy/legacy_cache_storage.h deleted file mode 100644 index 8e055c99..0000000 --- a/content/browser/cache_storage/legacy/legacy_cache_storage.h +++ /dev/null
@@ -1,351 +0,0 @@ -// Copyright 2014 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 CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_H_ -#define CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_H_ - -#include <stdint.h> - -#include <map> - -#include "base/files/file_path.h" -#include "base/gtest_prod_util.h" -#include "base/memory/memory_pressure_listener.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "build/build_config.h" -#include "components/services/storage/public/mojom/blob_storage_context.mojom.h" -#include "components/services/storage/public/mojom/cache_storage_control.mojom.h" -#include "content/browser/cache_storage/blob_storage_context_wrapper.h" -#include "content/browser/cache_storage/cache_storage.h" -#include "content/browser/cache_storage/cache_storage_cache_observer.h" -#include "content/browser/cache_storage/cache_storage_manager.h" -#include "content/browser/cache_storage/cache_storage_scheduler_types.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage_cache.h" -#include "content/common/content_export.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" - -#if BUILDFLAG(IS_ANDROID) -#include "base/android/application_status_listener.h" -#endif - -namespace base { -class SequencedTaskRunner; -} - -namespace content { -class CacheStorageIndex; -class CacheStorageScheduler; -class LegacyCacheStorageManager; - -namespace cache_storage_manager_unittest { -class CacheStorageManagerTest; -FORWARD_DECLARE_TEST(CacheStorageManagerTest, PersistedCacheKeyUsed); -FORWARD_DECLARE_TEST(CacheStorageManagerTest, PutResponseWithExistingFileTest); -FORWARD_DECLARE_TEST(CacheStorageManagerTest, TestErrorInitializingCache); -} // namespace cache_storage_manager_unittest - -// TODO(jkarlin): Constrain the total bytes used per storage key. - -// Concrete implementation of the CacheStorage abstract class. This is -// the legacy implementation using LegacyCacheStorageCache objects. -class CONTENT_EXPORT LegacyCacheStorage : public CacheStorage, - public CacheStorageCacheObserver { - public: - using SizeCallback = base::OnceCallback<void(int64_t)>; - - static const char kIndexFileName[]; - - LegacyCacheStorage( - const base::FilePath& origin_path, - bool memory_only, - base::SequencedTaskRunner* cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - LegacyCacheStorageManager* cache_storage_manager, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner); - - LegacyCacheStorage(const LegacyCacheStorage&) = delete; - LegacyCacheStorage& operator=(const LegacyCacheStorage&) = delete; - - // Any unfinished asynchronous operations may not complete or call their - // callbacks. - ~LegacyCacheStorage() override; - - CacheStorageHandle CreateHandle() override; - - // These methods are called by the CacheStorageHandle to track the number - // of outstanding references. - void AddHandleRef() override; - void DropHandleRef() override; - void AssertUnreferenced() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!handle_ref_count_); - } - - void Init() override; - - void OpenCache(const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback) override; - - void HasCache(const std::string& cache_name, - int64_t trace_id, - BoolAndErrorCallback callback) override; - - void DoomCache(const std::string& cache_name, - int64_t trace_id, - ErrorCallback callback) override; - - void EnumerateCaches(int64_t trace_id, - EnumerateCachesCallback callback) override; - - void MatchCache(const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) override; - - void MatchAllCaches(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback) override; - - void WriteToCache(const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - ErrorCallback callback) override; - - // Sums the sizes of each cache and closes them. Runs |callback| with the - // size. The sizes include any doomed caches and will also force close all - // caches even if there are existing handles to them. - void GetSizeThenCloseAllCaches(SizeCallback callback); - - // The size of all of the storage key's contents. This value should be used as - // an estimate only since the cache may be modified at any time. - void Size(SizeCallback callback); - - // The functions below are for tests to verify that the operations run - // serially. - CacheStorageSchedulerId StartAsyncOperationForTesting(); - void CompleteAsyncOperationForTesting(CacheStorageSchedulerId id); - - // Removes the manager reference. Called before this storage is deleted by the - // manager, since it is removed from manager's storage map before deleting. - void ResetManager(); - - // CacheStorageCacheObserver: - void CacheSizeUpdated(const LegacyCacheStorageCache* cache) override; - - // Destroy any CacheStorageCache instances that are not currently referenced - // by a CacheStorageCacheHandle. - void ReleaseUnreferencedCaches(); - - static LegacyCacheStorage* From(const CacheStorageHandle& handle) { - return static_cast<LegacyCacheStorage*>(handle.value()); - } - - protected: - // Virtual for testing - virtual void CacheUnreferenced(LegacyCacheStorageCache* cache); - - private: - friend class LegacyCacheStorageCache; - friend class cache_storage_manager_unittest::CacheStorageManagerTest; - FRIEND_TEST_ALL_PREFIXES( - cache_storage_manager_unittest::CacheStorageManagerTest, - PersistedCacheKeyUsed); - FRIEND_TEST_ALL_PREFIXES( - cache_storage_manager_unittest::CacheStorageManagerTest, - PutResponseWithExistingFileTest); - FRIEND_TEST_ALL_PREFIXES( - cache_storage_manager_unittest::CacheStorageManagerTest, - TestErrorInitializingCache); - class CacheLoader; - class MemoryLoader; - class SimpleCacheLoader; - struct CacheMatchResponse; - - typedef std::map<std::string, std::unique_ptr<LegacyCacheStorageCache>> - CacheMap; - - // Generate a new padding key. For testing only and *not thread safe*. - static void GenerateNewKeyForTesting(); - - // Returns a CacheStorageCacheHandle for the given name if the name is known. - // If the CacheStorageCache has been deleted, creates a new one. - CacheStorageCacheHandle GetLoadedCache(const std::string& cache_name); - - // Initializer and its callback are below. - void LazyInit(); - void LazyInitImpl(); - void LazyInitDidLoadIndex(std::unique_ptr<CacheStorageIndex> index); - - // The Open and CreateCache callbacks are below. - void OpenCacheImpl(const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback); - void CreateCacheDidCreateCache(const std::string& cache_name, - int64_t trace_id, - CacheAndErrorCallback callback, - std::unique_ptr<LegacyCacheStorageCache> cache, - blink::mojom::CacheStorageError status); - void CreateCacheDidWriteIndex(CacheAndErrorCallback callback, - CacheStorageCacheHandle cache_handle, - int64_t trace_id, - bool success); - - // The HasCache callbacks are below. - void HasCacheImpl(const std::string& cache_name, - int64_t trace_id, - BoolAndErrorCallback callback); - - // The DeleteCache callbacks are below. - void DoomCacheImpl(const std::string& cache_name, - int64_t trace_id, - ErrorCallback callback); - void DeleteCacheDidWriteIndex(CacheStorageCacheHandle cache_handle, - ErrorCallback callback, - int64_t trace_id, - bool success); - void DeleteCacheFinalize(LegacyCacheStorageCache* doomed_cache); - void DeleteCacheDidGetSize(LegacyCacheStorageCache* doomed_cache, - int64_t cache_size); - void DeleteCacheDidCleanUp(bool success); - - // The EnumerateCache callbacks are below. - void EnumerateCachesImpl(int64_t trace_id, EnumerateCachesCallback callback); - - // The MatchCache callbacks are below. - void MatchCacheImpl(const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback); - void MatchCacheDidMatch(CacheStorageCacheHandle cache_handle, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback, - blink::mojom::CacheStorageError error, - blink::mojom::FetchAPIResponsePtr response); - - // The MatchAllCaches callbacks are below. - void MatchAllCachesImpl(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback); - void MatchAllCachesDidMatch(CacheStorageCacheHandle cache_handle, - CacheMatchResponse* out_match_response, - const base::RepeatingClosure& barrier_closure, - int64_t trace_id, - blink::mojom::CacheStorageError error, - blink::mojom::FetchAPIResponsePtr response); - void MatchAllCachesDidMatchAll( - std::unique_ptr<std::vector<CacheMatchResponse>> match_responses, - int64_t trace_id, - CacheStorageCache::ResponseCallback callback); - - // WriteToCache callbacks. - void WriteToCacheImpl(const std::string& cache_name, - blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - ErrorCallback callback); - - void GetSizeThenCloseAllCachesImpl(SizeCallback callback); - - void SizeImpl(SizeCallback callback); - void SizeRetrievedFromCache(CacheStorageCacheHandle cache_handle, - base::OnceClosure closure, - int64_t* accumulator, - int64_t size); - - void NotifyCacheContentChanged(const std::string& cache_name); - - void ScheduleWriteIndex(); - void WriteIndex(base::OnceCallback<void(bool)> callback); - void WriteIndexImpl(base::OnceCallback<void(bool)> callback); - bool index_write_pending() const { return !index_write_task_.IsCancelled(); } - // Start a scheduled index write immediately. Returns true if a write was - // scheduled, or false if not. - bool InitiateScheduledIndexWriteForTest( - base::OnceCallback<void(bool)> callback); - - void FlushIndexIfDirty(); - -#if BUILDFLAG(IS_ANDROID) - void OnApplicationStateChange(base::android::ApplicationState state); -#endif - - // Whether or not we've loaded the list of cache names into memory. - bool initialized_; - bool initializing_; - - // True if the backend is supposed to reside in memory only. - bool memory_only_; - - // The pending operation scheduler. - std::unique_ptr<CacheStorageScheduler> scheduler_; - - // The map of cache names to CacheStorageCache objects. - CacheMap cache_map_; - - // Caches that have been deleted but must still be held onto until all handles - // have been released. - std::map<LegacyCacheStorageCache*, std::unique_ptr<LegacyCacheStorageCache>> - doomed_caches_; - - // The cache index data. - std::unique_ptr<CacheStorageIndex> cache_index_; - - // The file path for this CacheStorage. - base::FilePath origin_path_; - - // The TaskRunner to run file IO on. - scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; - - // Performs backend specific operations (memory vs disk). - std::unique_ptr<CacheLoader> cache_loader_; - - // The quota manager. - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; - - // An IO thread bound wrapper for storage.mojom.BlobStorageContext. - scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; - - // The owner that this CacheStorage is associated with. - storage::mojom::CacheStorageOwner owner_; - - CacheStorageSchedulerId init_id_ = -1; - - // The manager that owns this cache storage. Only set to null by - // RemoveManager() when this cache storage is being deleted. - raw_ptr<LegacyCacheStorageManager> cache_storage_manager_; - - base::CancelableOnceClosure index_write_task_; - size_t handle_ref_count_ = 0; - -#if BUILDFLAG(IS_ANDROID) - std::unique_ptr<base::android::ApplicationStatusListener> - app_status_listener_; -#endif - - // True if running on android and the app is in the background. - bool app_on_background_ = false; - - SEQUENCE_CHECKER(sequence_checker_); - base::WeakPtrFactory<LegacyCacheStorage> weak_factory_{this}; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_H_
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h deleted file mode 100644 index 515d7387..0000000 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h +++ /dev/null
@@ -1,563 +0,0 @@ -// Copyright 2014 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 CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_CACHE_H_ -#define CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_CACHE_H_ - -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include "base/callback.h" -#include "base/containers/id_map.h" -#include "base/files/file_path.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" -#include "components/services/storage/public/mojom/cache_storage_control.mojom.h" -#include "content/browser/cache_storage/blob_storage_context_wrapper.h" -#include "content/browser/cache_storage/cache_storage_cache.h" -#include "content/browser/cache_storage/cache_storage_handle.h" -#include "content/browser/cache_storage/cache_storage_manager.h" -#include "content/browser/cache_storage/scoped_writable_entry.h" -#include "content/common/content_export.h" -#include "net/base/completion_once_callback.h" -#include "net/base/io_buffer.h" -#include "net/disk_cache/disk_cache.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" -#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h" -#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" - -namespace storage { -class QuotaManagerProxy; -} // namespace storage - -namespace content { -class CacheStorageBlobToDiskCache; -class CacheStorageCacheEntryHandler; -class CacheStorageCacheObserver; -class CacheStorageScheduler; -class LegacyCacheStorage; -struct PutContext; - -namespace proto { -class CacheMetadata; -} // namespace proto - -namespace cache_storage_cache_unittest { -class TestCacheStorageCache; -class CacheStorageCacheTest; -} // namespace cache_storage_cache_unittest - -// Concrete implementation of the CacheStorageCache abstract class. This is -// the legacy implementation using disk_cache for the backend. -class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache { - public: - using SizeCallback = base::OnceCallback<void(int64_t)>; - using SizePaddingCallback = base::OnceCallback<void(int64_t, int64_t)>; - - static std::unique_ptr<LegacyCacheStorageCache> CreateMemoryCache( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - const std::string& cache_name, - LegacyCacheStorage* cache_storage, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context); - static std::unique_ptr<LegacyCacheStorageCache> CreatePersistentCache( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - const std::string& cache_name, - LegacyCacheStorage* cache_storage, - const base::FilePath& path, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - int64_t cache_size, - int64_t cache_padding); - static int32_t GetResponsePaddingVersion(); - - void Match(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - CacheStorageSchedulerPriority priority, - int64_t trace_id, - ResponseCallback callback) override; - - void MatchAll(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - int64_t trace_id, - ResponsesCallback callback) override; - - void WriteSideData(ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len) override; - - // TODO(nhiroki): This function should run all operations atomically. - // http://crbug.com/486637 - void BatchOperation(std::vector<blink::mojom::BatchOperationPtr> operations, - int64_t trace_id, - VerboseErrorCallback callback, - BadMessageCallback bad_message_callback) override; - void BatchDidGetUsageAndQuota( - std::vector<blink::mojom::BatchOperationPtr> operations, - int64_t trace_id, - VerboseErrorCallback callback, - BadMessageCallback bad_message_callback, - absl::optional<std::string> message, - uint64_t space_required, - uint64_t side_data_size, - blink::mojom::QuotaStatusCode status_code, - int64_t usage, - int64_t quota); - - void Keys(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - RequestsCallback callback) override; - - // Closes the backend. Future operations that require the backend - // will exit early. Close should only be called once per CacheStorageCache. - void Close(base::OnceClosure callback); - - // The size of the cache's contents. The callback reports the padded - // size. If you want the unpadded size you may call the cache_size() - // getter method on the cache object when the callback is invoked; the - // getter will have an up-to-date value at that point. - void Size(SizeCallback callback); - - // Gets the cache's size, closes the backend, and then runs |callback| with - // the cache's size. As per the comment for Size(), this also returns the - // padded size. - void GetSizeThenClose(SizeCallback callback); - - void Put(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::FetchAPIResponsePtr response, - int64_t trace_id, - ErrorCallback callback) override; - - void GetAllMatchedEntries(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - int64_t trace_id, - CacheEntriesCallback callback) override; - - InitState GetInitState() const override; - - LegacyCacheStorageCache(const LegacyCacheStorageCache&) = delete; - LegacyCacheStorageCache& operator=(const LegacyCacheStorageCache&) = delete; - - // Async operations in progress will cancel and not run their callbacks. - ~LegacyCacheStorageCache() override; - - base::FilePath path() const { return path_; } - - std::string cache_name() const { return cache_name_; } - - int64_t cache_size() const { return cache_size_; } - - int64_t cache_padding() const { return cache_padding_; } - - // Return the total cache size (actual size + padding). If either is unknown - // then CacheStorage::kSizeUnknown is returned. - int64_t PaddedCacheSize() const; - - // Set the one observer that will be notified of changes to this cache. - // Note: Either the observer must have a lifetime longer than this instance - // or call SetObserver(nullptr) to stop receiving notification of changes. - void SetObserver(CacheStorageCacheObserver* observer); - - static size_t EstimatedStructSize( - const blink::mojom::FetchAPIRequestPtr& request); - - base::WeakPtr<LegacyCacheStorageCache> AsWeakPtr(); - - CacheStorageCacheHandle CreateHandle() override; - void AddHandleRef() override; - void DropHandleRef() override; - bool IsUnreferenced() const override; - - // Override the default scheduler with a customized scheduler for testing. - // The current scheduler must be idle. - void SetSchedulerForTesting(std::unique_ptr<CacheStorageScheduler> scheduler); - - static LegacyCacheStorageCache* From(const CacheStorageCacheHandle& handle) { - return static_cast<LegacyCacheStorageCache*>(handle.value()); - } - - private: - // QueryCache types: - enum QueryCacheFlags { - QUERY_CACHE_REQUESTS = 0x1, - QUERY_CACHE_RESPONSES_WITH_BODIES = 0x2, - QUERY_CACHE_RESPONSES_NO_BODIES = 0x4, - QUERY_CACHE_ENTRIES = 0x8, - }; - - // The backend progresses from uninitialized, to open, to closed, and cannot - // reverse direction. The open step may be skipped. - enum BackendState { - BACKEND_UNINITIALIZED, // No backend, create backend on first operation. - BACKEND_OPEN, // Backend can be used. - BACKEND_CLOSED // Backend cannot be used. All ops should fail. - }; - - friend class base::RefCounted<CacheStorageCache>; - friend class cache_storage_cache_unittest::TestCacheStorageCache; - friend class cache_storage_cache_unittest::CacheStorageCacheTest; - - struct QueryCacheContext; - struct QueryCacheResult; - struct BatchInfo; - - using QueryTypes = int32_t; - using QueryCacheResults = std::vector<QueryCacheResult>; - using QueryCacheCallback = - base::OnceCallback<void(blink::mojom::CacheStorageError, - std::unique_ptr<QueryCacheResults>)>; - using Entries = std::vector<disk_cache::Entry*>; - using ScopedBackendPtr = std::unique_ptr<disk_cache::Backend>; - using BlobToDiskCacheIDMap = - base::IDMap<std::unique_ptr<CacheStorageBlobToDiskCache>>; - - LegacyCacheStorageCache( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - const std::string& cache_name, - const base::FilePath& path, - LegacyCacheStorage* cache_storage, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context, - int64_t cache_size, - int64_t cache_padding); - - // Callback passed to operations. If |error| is a real error, invokes - // |error_callback|. Always invokes |completion_closure| to signal - // completion. - void BatchDidOneOperation(BatchInfo& batch_status, - blink::mojom::CacheStorageError error); - - // Runs |callback| with matching requests/response data. The data provided - // in the QueryCacheResults depends on the |query_type|. If |query_type| is - // CACHE_ENTRIES then only out_entries is valid. If |query_type| is REQUESTS - // then only out_requests is valid. If |query_type| is - // REQUESTS_AND_RESPONSES then only out_requests, out_responses, and - // out_blob_data_handles are valid. - void QueryCache(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - QueryTypes query_types, - CacheStorageSchedulerPriority priority, - QueryCacheCallback callback); - void QueryCacheDidOpenFastPath( - std::unique_ptr<QueryCacheContext> query_cache_context, - disk_cache::EntryResult result); - void QueryCacheOpenNextEntry( - std::unique_ptr<QueryCacheContext> query_cache_context); - void QueryCacheFilterEntry( - std::unique_ptr<QueryCacheContext> query_cache_context, - disk_cache::EntryResult result); - void QueryCacheDidReadMetadata( - std::unique_ptr<QueryCacheContext> query_cache_context, - disk_cache::ScopedEntryPtr entry, - std::unique_ptr<proto::CacheMetadata> metadata); - void QueryCacheUpgradePadding( - std::unique_ptr<QueryCacheContext> query_cache_context, - disk_cache::ScopedEntryPtr entry, - std::unique_ptr<proto::CacheMetadata> metadata); - static bool QueryCacheResultCompare(const QueryCacheResult& lhs, - const QueryCacheResult& rhs); - static size_t EstimatedResponseSizeWithoutBlob( - const blink::mojom::FetchAPIResponse& response); - - // Match callbacks - void MatchImpl(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - int64_t trace_id, - CacheStorageSchedulerPriority priority, - ResponseCallback callback); - void MatchDidMatchAll( - ResponseCallback callback, - blink::mojom::CacheStorageError match_all_error, - std::vector<blink::mojom::FetchAPIResponsePtr> match_all_responses); - - // MatchAll callbacks - void MatchAllImpl(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - CacheStorageSchedulerPriority priority, - ResponsesCallback callback); - void MatchAllDidQueryCache( - ResponsesCallback callback, - int64_t trace_id, - blink::mojom::CacheStorageError error, - std::unique_ptr<QueryCacheResults> query_cache_results); - - // Utility method to write metadata headers to an entry. - using WriteMetadataCallback = - base::OnceCallback<void(int exepected_bytes, int rv)>; - void WriteMetadata(disk_cache::Entry* entry, - const proto::CacheMetadata& metadata, - WriteMetadataCallback callback); - - // WriteSideData callbacks - void WriteSideDataDidGetQuota(ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len, - blink::mojom::QuotaStatusCode status_code, - int64_t usage, - int64_t quota); - - void WriteSideDataImpl(ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len); - void WriteSideDataDidGetUsageAndQuota( - ErrorCallback callback, - const GURL& url, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len, - blink::mojom::QuotaStatusCode status_code, - int64_t usage, - int64_t quota); - void WriteSideDataDidOpenEntry(ErrorCallback callback, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len, - disk_cache::EntryResult result); - void WriteSideDataDidReadMetaData( - ErrorCallback callback, - base::Time expected_response_time, - int64_t trace_id, - scoped_refptr<net::IOBuffer> buffer, - int buf_len, - ScopedWritableEntry entry, - std::unique_ptr<proto::CacheMetadata> headers); - void WriteSideDataDidWrite( - ErrorCallback callback, - ScopedWritableEntry entry, - int expected_bytes, - std::unique_ptr<content::proto::CacheMetadata> metadata, - int64_t trace_id, - int rv); - void WriteSideDataDidWriteMetadata(ErrorCallback callback, - ScopedWritableEntry entry, - int64_t padding, - int64_t side_data_padding, - int expected_bytes, - int rv); - void WriteSideDataComplete(ErrorCallback callback, - ScopedWritableEntry entry, - int64_t padding, - int64_t side_data_padding, - blink::mojom::CacheStorageError error); - - // Puts the request and response object in the cache. The response body (if - // present) is stored in the cache, but not the request body. Returns OK on - // success. - void Put(blink::mojom::BatchOperationPtr operation, - int64_t trace_id, - ErrorCallback callback); - void PutImpl(std::unique_ptr<PutContext> put_context); - void PutDidDeleteEntry(std::unique_ptr<PutContext> put_context, - blink::mojom::CacheStorageError error); - void PutDidGetUsageAndQuota(std::unique_ptr<PutContext> put_context, - blink::mojom::QuotaStatusCode status_code, - int64_t usage, - int64_t quota); - void PutDidCreateEntry(std::unique_ptr<PutContext> put_context, - disk_cache::EntryResult result); - void PutDidWriteHeaders(std::unique_ptr<PutContext> put_context, - int64_t padding, - int64_t side_data_padding, - int expected_bytes, - int rv); - void PutWriteBlobToCache(std::unique_ptr<PutContext> put_context, - int disk_cache_body_index); - void PutDidWriteBlobToCache(std::unique_ptr<PutContext> put_context, - BlobToDiskCacheIDMap::KeyType blob_to_cache_key, - int disk_cache_body_index, - ScopedWritableEntry entry, - bool success); - void PutWriteBlobToCacheComplete(std::unique_ptr<PutContext> put_context, - int disk_cache_body_index, - ScopedWritableEntry entry, - int rv); - void PutComplete(std::unique_ptr<PutContext> put_context, - blink::mojom::CacheStorageError error); - - // Asynchronously calculates the current cache size, notifies the quota - // manager of any change from the last report, and sets cache_size_ to the new - // size. - void UpdateCacheSize(base::OnceClosure callback); - void UpdateCacheSizeGotSize(CacheStorageCacheHandle, - base::OnceClosure callback, - int64_t current_cache_size); - void UpdateCacheSizeNotifiedStorageModified(base::OnceClosure callback); - - // GetAllMatchedEntries callbacks. - void GetAllMatchedEntriesImpl(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - CacheEntriesCallback callback); - void GetAllMatchedEntriesDidQueryCache( - int64_t trace_id, - CacheEntriesCallback callback, - blink::mojom::CacheStorageError error, - std::unique_ptr<QueryCacheResults> query_cache_results); - - // Returns ERROR_NOT_FOUND if not found. Otherwise deletes and returns OK. - void Delete(blink::mojom::BatchOperationPtr operation, - ErrorCallback callback); - void DeleteImpl(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr match_options, - ErrorCallback callback); - void DeleteDidQueryCache( - ErrorCallback callback, - blink::mojom::CacheStorageError error, - std::unique_ptr<QueryCacheResults> query_cache_results); - - // Keys callbacks. - void KeysImpl(blink::mojom::FetchAPIRequestPtr request, - blink::mojom::CacheQueryOptionsPtr options, - int64_t trace_id, - RequestsCallback callback); - void KeysDidQueryCache( - RequestsCallback callback, - int64_t trace_id, - blink::mojom::CacheStorageError error, - std::unique_ptr<QueryCacheResults> query_cache_results); - - void CloseImpl(base::OnceClosure callback); - - void SizeImpl(SizeCallback callback); - - void GetSizeThenCloseDidGetSize(SizeCallback callback, int64_t cache_size); - - // Loads the backend and calls the callback with the result (true for - // success). The callback will always be called. Virtual for tests. - virtual void CreateBackend(ErrorCallback callback); - void CreateBackendDidCreate(ErrorCallback callback, - std::unique_ptr<ScopedBackendPtr> backend_ptr, - int rv); - - // Calculate the size and padding of the cache. - void CalculateCacheSizePadding(SizePaddingCallback callback); - void CalculateCacheSizePaddingGotSize(SizePaddingCallback callback, - int64_t cache_size); - void PaddingDidQueryCache( - SizePaddingCallback callback, - int64_t cache_size, - blink::mojom::CacheStorageError error, - std::unique_ptr<QueryCacheResults> query_cache_results); - - // Calculate the size (but not padding) of the cache. - void CalculateCacheSize(net::Int64CompletionOnceCallback callback); - - void InitBackend(); - void InitDidCreateBackend(base::OnceClosure callback, - blink::mojom::CacheStorageError cache_create_error); - void InitGotCacheSize(base::OnceClosure callback, - blink::mojom::CacheStorageError cache_create_error, - int64_t cache_size); - void InitGotCacheSizeAndPadding( - base::OnceClosure callback, - blink::mojom::CacheStorageError cache_create_error, - int64_t cache_size, - int64_t cache_padding); - void DeleteBackendCompletedIO(); - - // Calculate the required safe space to put the entry in the cache. - base::CheckedNumeric<uint64_t> CalculateRequiredSafeSpaceForPut( - const blink::mojom::BatchOperationPtr& operation); - base::CheckedNumeric<uint64_t> CalculateRequiredSafeSpaceForRequest( - const blink::mojom::FetchAPIRequestPtr& request); - base::CheckedNumeric<uint64_t> CalculateRequiredSafeSpaceForResponse( - const blink::mojom::FetchAPIResponsePtr& response); - - // Wrap |callback| in order to reference a CacheStorageCacheHandle - // for the duration of an asynchronous operation. We must keep this - // self reference for a couple reasons. First, we must allow any writes - // to cleanly complete in order to avoid truncated entries. In addition, - // we must keep the cache and its disk_cache backend alive until all - // open Entry objects are destroyed to avoid having a second backend - // opened by another CacheStorageCache clobbering the entries. - template <typename... Args> - base::OnceCallback<void(Args...)> WrapCallbackWithHandle( - base::OnceCallback<void(Args...)> callback) { - return base::BindOnce(&LegacyCacheStorageCache::RunWithHandle<Args...>, - weak_ptr_factory_.GetWeakPtr(), CreateHandle(), - std::move(callback)); - } - - // Invoked by wrapped callbacks with the CacheStorageCacheHandle passed - // as a parameter. The handle is kept alive here simply to maintain - // a self-reference during the operation. - template <typename... Args> - void RunWithHandle(CacheStorageCacheHandle handle, - base::OnceCallback<void(Args...)> callback, - Args... args) { - std::move(callback).Run(std::forward<Args>(args)...); - // |handle| is destroyed after running the inner wrapped callback. - } - - // Be sure to check |backend_state_| before use. - std::unique_ptr<disk_cache::Backend> backend_; - - blink::StorageKey storage_key_; - storage::mojom::CacheStorageOwner owner_; - const std::string cache_name_; - base::FilePath path_; - - // Raw pointer is safe because the CacheStorage instance owns this - // CacheStorageCache object. - raw_ptr<LegacyCacheStorage> cache_storage_; - - // A handle that is used to keep the owning CacheStorage instance referenced - // as long this cache object is also referenced. - CacheStorageHandle cache_storage_handle_; - - const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; - BackendState backend_state_ = BACKEND_UNINITIALIZED; - std::unique_ptr<CacheStorageScheduler> scheduler_; - bool initializing_ = false; - // The actual cache size (not including padding). - int64_t cache_size_; - int64_t cache_padding_ = 0; - int64_t last_reported_size_ = 0; - size_t max_query_size_bytes_; - size_t handle_ref_count_ = 0; - int query_cache_recursive_depth_ = 0; - raw_ptr<CacheStorageCacheObserver> cache_observer_; - std::unique_ptr<CacheStorageCacheEntryHandler> cache_entry_handler_; - - // Owns the elements of the list - BlobToDiskCacheIDMap active_blob_to_disk_cache_writers_; - - // Whether or not to store data in disk or memory. - bool memory_only_; - - // Active while waiting for the backend to finish its closing up, and contains - // the callback passed to CloseImpl. - base::OnceClosure post_backend_closed_callback_; - - SEQUENCE_CHECKER(sequence_checker_); - base::WeakPtrFactory<LegacyCacheStorageCache> weak_ptr_factory_{this}; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_CACHE_H_
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc deleted file mode 100644 index 5bfad25d6..0000000 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc +++ /dev/null
@@ -1,605 +0,0 @@ -// Copyright 2014 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 "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h" - -#include <stdint.h> - -#include <map> -#include <numeric> -#include <set> -#include <utility> - -#include "base/barrier_closure.h" -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/containers/id_map.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_util.h" -#include "base/hash/sha1.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_functions.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/task/sequenced_task_runner.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/time/time.h" -#include "components/services/storage/public/cpp/constants.h" -#include "content/browser/cache_storage/cache_storage.h" -#include "content/browser/cache_storage/cache_storage.pb.h" -#include "content/browser/cache_storage/cache_storage_quota_client.h" -#include "storage/browser/quota/quota_manager_proxy.h" -#include "storage/common/database/database_identifier.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" -#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" -#include "url/gurl.h" -#include "url/origin.h" - -namespace content { - -namespace { - -bool DeleteDir(const base::FilePath& path) { - return base::DeletePathRecursively(path); -} - -void DeleteStorageKeyDidDeleteDir( - storage::mojom::QuotaClient::DeleteBucketDataCallback callback, - bool rv) { - // On scheduler sequence. - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - rv ? blink::mojom::QuotaStatusCode::kOk - : blink::mojom::QuotaStatusCode::kErrorAbort)); -} - -// Calculate the sum of all cache sizes in this store, but only if all sizes are -// known. If one or more sizes are not known then return kSizeUnknown. -int64_t GetCacheStorageSize(const base::FilePath& base_path, - const base::Time& index_time, - const proto::CacheStorageIndex& index) { - // Note, do not use the base path time modified to invalidate the index file. - // On some platforms the directory modified time will be slightly later than - // the last modified time of a file within it. This means any write to the - // index file will also update the directory modify time slightly after - // immediately invalidating it. To avoid this we only look at the cache - // directories and not the base directory containing the index itself. - int64_t storage_size = 0; - for (int i = 0, max = index.cache_size(); i < max; ++i) { - const proto::CacheStorageIndex::Cache& cache = index.cache(i); - if (!cache.has_cache_dir() || !cache.has_size() || - cache.size() == CacheStorage::kSizeUnknown || !cache.has_padding() || - cache.padding() == CacheStorage::kSizeUnknown) { - return CacheStorage::kSizeUnknown; - } - - // Check the modified time on each cache directory. If one of the - // directories has the same or newer modified time as the index file, then - // its size is most likely not accounted for in the index file. The - // cache can have a newer time here in spite of our base path time check - // above since simple disk_cache writes to these directories from a - // different thread. - base::FilePath path = base_path.AppendASCII(cache.cache_dir()); - base::File::Info file_info; - if (!base::GetFileInfo(path, &file_info) || - file_info.last_modified >= index_time) { - return CacheStorage::kSizeUnknown; - } - - storage_size += (cache.size() + cache.padding()); - } - - return storage_size; -} - -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class IndexResult { - kOk = 0, - kFailedToParse = 1, - kMissingOrigin = 2, - kEmptyOriginUrl = 3, - kPathMismatch = 4, - kPathFileInfoFailed = 5, - // Add new enums above - kMaxValue = kPathFileInfoFailed, -}; - -IndexResult ValidateIndex(proto::CacheStorageIndex index) { - if (!index.has_origin()) - return IndexResult::kMissingOrigin; - - GURL url(index.origin()); - if (url.is_empty()) - return IndexResult::kEmptyOriginUrl; - - return IndexResult::kOk; -} - -void RecordIndexValidationResult(IndexResult value) { - base::UmaHistogramEnumeration("ServiceWorkerCache.ListOriginsIndexValidity", - value); -} - -// Open the various cache directories' index files and extract their storage -// keys, sizes (if current), and last modified times. -std::vector<storage::mojom::StorageUsageInfoPtr> -GetStorageKeysAndLastModifiedOnTaskRunner( - std::vector<storage::mojom::StorageUsageInfoPtr> usages, - base::FilePath root_path, - storage::mojom::CacheStorageOwner owner) { - base::FileEnumerator file_enum(root_path, false /* recursive */, - base::FileEnumerator::DIRECTORIES); - - base::FilePath path; - while (!(path = file_enum.Next()).empty()) { - base::FilePath index_path = - path.AppendASCII(LegacyCacheStorage::kIndexFileName); - base::File::Info file_info; - base::Time index_last_modified; - if (GetFileInfo(index_path, &file_info)) - index_last_modified = file_info.last_modified; - std::string protobuf; - base::ReadFileToString(path.AppendASCII(LegacyCacheStorage::kIndexFileName), - &protobuf); - - proto::CacheStorageIndex index; - if (!index.ParseFromString(protobuf)) { - RecordIndexValidationResult(IndexResult::kFailedToParse); - continue; - } - - IndexResult rv = ValidateIndex(index); - if (rv != IndexResult::kOk) { - RecordIndexValidationResult(rv); - continue; - } - - auto storage_key = - blink::StorageKey(url::Origin::Create(GURL(index.origin()))); - DCHECK(!storage_key.origin().GetURL().is_empty()); - - auto origin_path = LegacyCacheStorageManager::ConstructStorageKeyPath( - root_path, storage_key, owner); - if (path != origin_path) { - storage::mojom::CacheStorageOwner other_owner = - owner == storage::mojom::CacheStorageOwner::kCacheAPI - ? storage::mojom::CacheStorageOwner::kBackgroundFetch - : storage::mojom::CacheStorageOwner::kCacheAPI; - auto other_owner_path = - LegacyCacheStorageManager::ConstructStorageKeyPath( - root_path, storage_key, other_owner); - // Some of the paths in the |root_path| directory are for a different - // |owner|. That is valid and expected, but if the path doesn't match - // the calculated path for either |owner|, then it is invalid. - if (path != other_owner_path) - RecordIndexValidationResult(IndexResult::kPathMismatch); - continue; - } - - int64_t storage_size = - GetCacheStorageSize(path, index_last_modified, index); - - usages.emplace_back(storage::mojom::StorageUsageInfo::New( - storage_key.origin(), storage_size, file_info.last_modified)); - RecordIndexValidationResult(IndexResult::kOk); - } - - return usages; -} - -std::vector<blink::StorageKey> ListStorageKeysOnTaskRunner( - base::FilePath root_path, - storage::mojom::CacheStorageOwner owner) { - std::vector<storage::mojom::StorageUsageInfoPtr> usages = - GetStorageKeysAndLastModifiedOnTaskRunner( - std::vector<storage::mojom::StorageUsageInfoPtr>(), root_path, owner); - - std::vector<blink::StorageKey> out_storage_keys; - for (const storage::mojom::StorageUsageInfoPtr& usage : usages) - out_storage_keys.emplace_back(blink::StorageKey(usage->origin)); - - return out_storage_keys; -} - -void AllOriginSizesReported( - std::vector<storage::mojom::StorageUsageInfoPtr> usages, - storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback - callback) { - // On scheduler sequence. - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), std::move(usages))); -} - -void OneOriginSizeReported(base::OnceClosure callback, - storage::mojom::StorageUsageInfoPtr* usage, - int64_t size) { - // On scheduler sequence. - DCHECK_NE(size, CacheStorage::kSizeUnknown); - (*usage)->total_size_bytes = size; - base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, - std::move(callback)); -} - -} // namespace - -// static -scoped_refptr<LegacyCacheStorageManager> LegacyCacheStorageManager::Create( - const base::FilePath& path, - scoped_refptr<base::SequencedTaskRunner> cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context) { - DCHECK(cache_task_runner); - DCHECK(scheduler_task_runner); - DCHECK(quota_manager_proxy); - DCHECK(blob_storage_context); - - base::FilePath root_path = path; - if (!path.empty()) { - root_path = path.Append(storage::kServiceWorkerDirectory) - .AppendASCII("CacheStorage"); - } - - return base::WrapRefCounted(new LegacyCacheStorageManager( - root_path, std::move(cache_task_runner), std::move(scheduler_task_runner), - std::move(quota_manager_proxy), std::move(blob_storage_context))); -} - -// static -scoped_refptr<LegacyCacheStorageManager> -LegacyCacheStorageManager::CreateForTesting( - LegacyCacheStorageManager* old_manager) { - scoped_refptr<LegacyCacheStorageManager> manager( - new LegacyCacheStorageManager(old_manager->root_path(), - old_manager->cache_task_runner(), - old_manager->scheduler_task_runner(), - old_manager->quota_manager_proxy_, - old_manager->blob_storage_context_)); - return manager; -} - -LegacyCacheStorageManager::~LegacyCacheStorageManager() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); -} - -CacheStorageHandle LegacyCacheStorageManager::OpenCacheStorage( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // Wait to create the MemoryPressureListener until the first CacheStorage - // object is needed. This ensures we create the listener on the correct - // thread. - if (!memory_pressure_listener_) { - memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( - FROM_HERE, - base::BindRepeating(&LegacyCacheStorageManager::OnMemoryPressure, - base::Unretained(this))); - } - - CacheStorageMap::const_iterator it = - cache_storage_map_.find({storage_key, owner}); - if (it == cache_storage_map_.end()) { - LegacyCacheStorage* cache_storage = new LegacyCacheStorage( - ConstructStorageKeyPath(root_path_, storage_key, owner), - IsMemoryBacked(), cache_task_runner_.get(), scheduler_task_runner_, - quota_manager_proxy_, blob_storage_context_, this, storage_key, owner); - cache_storage_map_[{storage_key, owner}] = base::WrapUnique(cache_storage); - return cache_storage->CreateHandle(); - } - return it->second.get()->CreateHandle(); -} - -void LegacyCacheStorageManager::NotifyCacheListChanged( - const blink::StorageKey& storage_key) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - for (const auto& observer : observers_) - observer->OnCacheListChanged(storage_key); -} - -void LegacyCacheStorageManager::NotifyCacheContentChanged( - const blink::StorageKey& storage_key, - const std::string& name) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - for (const auto& observer : observers_) - observer->OnCacheContentChanged(storage_key, name); -} - -void LegacyCacheStorageManager::CacheStorageUnreferenced( - LegacyCacheStorage* cache_storage, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(cache_storage); - cache_storage->AssertUnreferenced(); - auto it = cache_storage_map_.find({storage_key, owner}); - DCHECK(it != cache_storage_map_.end()); - DCHECK(it->second.get() == cache_storage); - - // Currently we don't do anything when a CacheStorage instance becomes - // unreferenced. In the future we will deallocate some or all of the - // CacheStorage's state. -} - -void LegacyCacheStorageManager::GetAllStorageKeysUsage( - storage::mojom::CacheStorageOwner owner, - storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback - callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<storage::mojom::StorageUsageInfoPtr> usages; - - if (IsMemoryBacked()) { - for (const auto& storage_keys_details : cache_storage_map_) { - if (storage_keys_details.first.second != owner) - continue; - usages.emplace_back(storage::mojom::StorageUsageInfo::New( - storage_keys_details.first.first.origin(), - /*total_size_bytes=*/0, - /*last_modified=*/base::Time())); - } - GetAllStorageKeysUsageGetSizes(std::move(callback), std::move(usages)); - return; - } - - cache_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&GetStorageKeysAndLastModifiedOnTaskRunner, - std::move(usages), root_path_, owner), - base::BindOnce(&LegacyCacheStorageManager::GetAllStorageKeysUsageGetSizes, - base::WrapRefCounted(this), std::move(callback))); -} - -void LegacyCacheStorageManager::GetAllStorageKeysUsageGetSizes( - storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback callback, - std::vector<storage::mojom::StorageUsageInfoPtr> usages) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // The origin GURL and last modified times are set in |usages| but not the - // size in bytes. Call each CacheStorage's Size() function to fill that out. - - if (usages.empty()) { - scheduler_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), std::move(usages))); - return; - } - - auto* usages_ptr = &usages[0]; - size_t usages_count = usages.size(); - base::RepeatingClosure barrier_closure = base::BarrierClosure( - usages_count, base::BindOnce(&AllOriginSizesReported, std::move(usages), - std::move(callback))); - - for (size_t i = 0; i < usages_count; ++i) { - auto& usage = usages_ptr[i]; - if (usage->total_size_bytes != CacheStorage::kSizeUnknown || - !IsValidQuotaStorageKey(blink::StorageKey(usage->origin))) { - scheduler_task_runner_->PostTask(FROM_HERE, barrier_closure); - continue; - } - CacheStorageHandle cache_storage = - OpenCacheStorage(blink::StorageKey(usage->origin), - storage::mojom::CacheStorageOwner::kCacheAPI); - LegacyCacheStorage::From(cache_storage) - ->Size(base::BindOnce(&OneOriginSizeReported, barrier_closure, &usage)); - } -} - -void LegacyCacheStorageManager::GetStorageKeyUsage( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetBucketUsageCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (IsMemoryBacked()) { - auto it = cache_storage_map_.find({storage_key, owner}); - if (it == cache_storage_map_.end()) { - scheduler_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), - /*usage=*/0)); - return; - } - CacheStorageHandle cache_storage = OpenCacheStorage(storage_key, owner); - LegacyCacheStorage::From(cache_storage)->Size(std::move(callback)); - return; - } - cache_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&base::PathExists, - ConstructStorageKeyPath(root_path_, storage_key, owner)), - base::BindOnce(&LegacyCacheStorageManager::GetStorageKeyUsageDidGetExists, - base::WrapRefCounted(this), storage_key, owner, - std::move(callback))); -} - -void LegacyCacheStorageManager::GetStorageKeyUsageDidGetExists( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetBucketUsageCallback callback, - bool exists) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!exists) { - scheduler_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), /*usage=*/0)); - return; - } - CacheStorageHandle cache_storage = OpenCacheStorage(storage_key, owner); - LegacyCacheStorage::From(cache_storage)->Size(std::move(callback)); -} - -void LegacyCacheStorageManager::GetStorageKeys( - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetStorageKeysForTypeCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (IsMemoryBacked()) { - std::vector<blink::StorageKey> storage_keys; - for (const auto& key_value : cache_storage_map_) - if (key_value.first.second == owner) - storage_keys.push_back(key_value.first.first); - - scheduler_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), std::move(storage_keys))); - return; - } - - PostTaskAndReplyWithResult( - cache_task_runner_.get(), FROM_HERE, - base::BindOnce(&ListStorageKeysOnTaskRunner, root_path_, owner), - std::move(callback)); -} - -void LegacyCacheStorageManager::DeleteStorageKeyData( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (IsMemoryBacked()) { - auto it = cache_storage_map_.find({storage_key, owner}); - if (it == cache_storage_map_.end()) { - scheduler_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), - blink::mojom::QuotaStatusCode::kOk)); - return; - } - DeleteStorageKeyDataDidGetExists(storage_key, owner, std::move(callback), - /*exists=*/true); - return; - } - - cache_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&base::PathExists, - ConstructStorageKeyPath(root_path_, storage_key, owner)), - base::BindOnce( - &LegacyCacheStorageManager::DeleteStorageKeyDataDidGetExists, - base::WrapRefCounted(this), storage_key, owner, std::move(callback))); -} - -void LegacyCacheStorageManager::DeleteStorageKeyDataDidGetExists( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback, - bool exists) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!exists) { - scheduler_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), - blink::mojom::QuotaStatusCode::kOk)); - return; - } - - // Create the CacheStorage for the storage key if it hasn't been loaded yet. - CacheStorageHandle handle = OpenCacheStorage(storage_key, owner); - - auto it = cache_storage_map_.find({storage_key, owner}); - DCHECK(it != cache_storage_map_.end()); - - LegacyCacheStorage* cache_storage = it->second.release(); - cache_storage->ResetManager(); - cache_storage_map_.erase({storage_key, owner}); - cache_storage->GetSizeThenCloseAllCaches( - base::BindOnce(&LegacyCacheStorageManager::DeleteStorageKeyDidClose, - base::WrapRefCounted(this), storage_key, owner, - std::move(callback), base::WrapUnique(cache_storage))); -} - -void LegacyCacheStorageManager::DeleteStorageKeyData( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DeleteStorageKeyData(storage_key, owner, base::DoNothing()); -} - -void LegacyCacheStorageManager::AddObserver( - mojo::PendingRemote<storage::mojom::CacheStorageObserver> observer) { - observers_.Add(std::move(observer)); -} - -void LegacyCacheStorageManager::DeleteStorageKeyDidClose( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback, - std::unique_ptr<LegacyCacheStorage> cache_storage, - int64_t origin_size) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(jkarlin): Deleting the storage leaves any unfinished operations - // hanging, resulting in unresolved promises. Fix this by returning early from - // CacheStorage operations posted after GetSizeThenCloseAllCaches is called. - cache_storage.reset(); - - quota_manager_proxy_->NotifyStorageModified( - CacheStorageQuotaClient::GetClientTypeFromOwner(owner), storage_key, - blink::mojom::StorageType::kTemporary, -origin_size, base::Time::Now(), - base::SequencedTaskRunnerHandle::Get(), base::DoNothing()); - - if (owner == storage::mojom::CacheStorageOwner::kCacheAPI) - NotifyCacheListChanged(storage_key); - - if (IsMemoryBacked()) { - scheduler_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), - blink::mojom::QuotaStatusCode::kOk)); - return; - } - - PostTaskAndReplyWithResult( - cache_task_runner_.get(), FROM_HERE, - base::BindOnce(&DeleteDir, - ConstructStorageKeyPath(root_path_, storage_key, owner)), - base::BindOnce(&DeleteStorageKeyDidDeleteDir, std::move(callback))); -} - -LegacyCacheStorageManager::LegacyCacheStorageManager( - const base::FilePath& path, - scoped_refptr<base::SequencedTaskRunner> cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context) - : root_path_(path), - cache_task_runner_(std::move(cache_task_runner)), - scheduler_task_runner_(std::move(scheduler_task_runner)), - quota_manager_proxy_(std::move(quota_manager_proxy)), - blob_storage_context_(std::move(blob_storage_context)) { - DCHECK(cache_task_runner_); - DCHECK(scheduler_task_runner_); - DCHECK(quota_manager_proxy_); - DCHECK(blob_storage_context_); -} - -// static -base::FilePath LegacyCacheStorageManager::ConstructStorageKeyPath( - const base::FilePath& root_path, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) { - // TODO(https://crbug.com/1199077): This identifier needs to be updated to - // include the full serialization of `storage_key`. - std::string identifier = - storage::GetIdentifierFromOrigin(storage_key.origin()); - if (owner != storage::mojom::CacheStorageOwner::kCacheAPI) { - identifier += "-" + std::to_string(static_cast<int>(owner)); - } - const std::string origin_hash = base::SHA1HashString(identifier); - const std::string origin_hash_hex = base::ToLowerASCII( - base::HexEncode(origin_hash.c_str(), origin_hash.length())); - return root_path.AppendASCII(origin_hash_hex); -} - -void LegacyCacheStorageManager::OnMemoryPressure( - base::MemoryPressureListener::MemoryPressureLevel level) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) - return; - - for (auto& entry : cache_storage_map_) { - entry.second->ReleaseUnreferencedCaches(); - } -} - -} // namespace content
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h deleted file mode 100644 index 3815214..0000000 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h +++ /dev/null
@@ -1,183 +0,0 @@ -// Copyright 2014 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 CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_MANAGER_H_ -#define CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_MANAGER_H_ - -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "base/memory/memory_pressure_listener.h" -#include "base/memory/scoped_refptr.h" -#include "base/sequence_checker.h" -#include "components/services/storage/public/mojom/cache_storage_control.mojom.h" -#include "components/services/storage/public/mojom/quota_client.mojom.h" -#include "components/services/storage/public/mojom/storage_usage_info.mojom.h" -#include "content/browser/cache_storage/blob_storage_context_wrapper.h" -#include "content/browser/cache_storage/cache_storage_context_impl.h" -#include "content/browser/cache_storage/cache_storage_manager.h" -#include "content/browser/cache_storage/legacy/legacy_cache_storage.h" -#include "content/common/content_export.h" -#include "content/public/browser/browser_thread.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "mojo/public/cpp/bindings/remote_set.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" - -namespace base { -class SequencedTaskRunner; -} - -namespace content { - -namespace cache_storage_manager_unittest { -class CacheStorageManagerTest; -} - -// A concrete implementation of the CacheStorageManager interface using -// the legacy disk_cache backend. -class CONTENT_EXPORT LegacyCacheStorageManager : public CacheStorageManager { - public: - static scoped_refptr<LegacyCacheStorageManager> Create( - const base::FilePath& path, - scoped_refptr<base::SequencedTaskRunner> cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context); - - // Create a new manager using the underlying configuration of the given - // manager, but with its own list of storage objects. This is only used - // for testing. - static scoped_refptr<LegacyCacheStorageManager> CreateForTesting( - LegacyCacheStorageManager* old_manager); - - LegacyCacheStorageManager(const LegacyCacheStorageManager&) = delete; - LegacyCacheStorageManager& operator=(const LegacyCacheStorageManager&) = - delete; - - // Map a database identifier (computed from a storage key) to the path. - static base::FilePath ConstructStorageKeyPath( - const base::FilePath& root_path, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner); - - // Open the CacheStorage for the given storage_key and owner. A reference - // counting handle is returned which can be stored and used similar to a weak - // pointer. - CacheStorageHandle OpenCacheStorage( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) override; - - void GetAllStorageKeysUsage( - storage::mojom::CacheStorageOwner owner, - storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback - callback) override; - void GetStorageKeyUsage( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetBucketUsageCallback callback) override; - void GetStorageKeys(storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetStorageKeysForTypeCallback - callback) override; - void DeleteStorageKeyData( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback) override; - void DeleteStorageKeyData(const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner) override; - void AddObserver(mojo::PendingRemote<storage::mojom::CacheStorageObserver> - observer) override; - - void NotifyCacheListChanged(const blink::StorageKey& storage_key); - void NotifyCacheContentChanged(const blink::StorageKey& storage_key, - const std::string& name); - - base::FilePath root_path() const { return root_path_; } - - // This method is called when the last CacheStorageHandle for a particular - // instance is destroyed and its reference count drops to zero. - void CacheStorageUnreferenced(LegacyCacheStorage* cache_storage, - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner); - - private: - friend class cache_storage_manager_unittest::CacheStorageManagerTest; - friend class CacheStorageContextImpl; - - typedef std::map< - std::pair<blink::StorageKey, storage::mojom::CacheStorageOwner>, - std::unique_ptr<LegacyCacheStorage>> - CacheStorageMap; - - LegacyCacheStorageManager( - const base::FilePath& path, - scoped_refptr<base::SequencedTaskRunner> cache_task_runner, - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, - scoped_refptr<BlobStorageContextWrapper> blob_storage_context); - - ~LegacyCacheStorageManager() override; - - void GetAllStorageKeysUsageGetSizes( - storage::mojom::CacheStorageControl::GetAllStorageKeysInfoCallback - callback, - std::vector<storage::mojom::StorageUsageInfoPtr> usage_info); - - void GetStorageKeyUsageDidGetExists( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::GetBucketUsageCallback callback, - bool exists); - - void DeleteStorageKeyDataDidGetExists( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback, - bool exists); - - void DeleteStorageKeyDidClose( - const blink::StorageKey& storage_key, - storage::mojom::CacheStorageOwner owner, - storage::mojom::QuotaClient::DeleteBucketDataCallback callback, - std::unique_ptr<LegacyCacheStorage> cache_storage, - int64_t origin_size); - - scoped_refptr<base::SequencedTaskRunner> cache_task_runner() const { - return cache_task_runner_; - } - - scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner() const { - return scheduler_task_runner_; - } - - bool IsMemoryBacked() const { return root_path_.empty(); } - - // MemoryPressureListener callback - void OnMemoryPressure( - base::MemoryPressureListener::MemoryPressureLevel level); - - base::FilePath root_path_; - const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; - const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; - - const scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; - - // The map owns the CacheStorages and the CacheStorages are only accessed on - // |cache_task_runner_|. - CacheStorageMap cache_storage_map_; - - mojo::RemoteSet<storage::mojom::CacheStorageObserver> observers_; - - const scoped_refptr<BlobStorageContextWrapper> blob_storage_context_; - - std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; - - SEQUENCE_CHECKER(sequence_checker_); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_CACHE_STORAGE_LEGACY_LEGACY_CACHE_STORAGE_MANAGER_H_
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc index d4a5aee..59c7ffb 100644 --- a/content/browser/first_party_sets/first_party_sets_handler_impl.cc +++ b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
@@ -98,13 +98,23 @@ SetPersistedSets(user_data_dir); SetManuallySpecifiedSet(flag_value); - if (!IsFirstPartySetsEnabled()) + if (!IsEnabled()) SetCompleteSets({}); } +bool FirstPartySetsHandlerImpl::IsEnabled() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // This method checks whether First-Party Sets are enabled, and memoizes the + // returned value in `enabled_`. + if (!enabled_.has_value()) { + enabled_ = GetContentClient()->browser()->IsFirstPartySetsEnabled(); + } + return enabled_.value(); +} + void FirstPartySetsHandlerImpl::SetPublicFirstPartySets(base::File sets_file) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!IsFirstPartySetsEnabled()) { + if (!IsEnabled()) { sets_loader_->DisposeFile(std::move(sets_file)); return; } @@ -121,10 +131,22 @@ policy, /*out_sets=*/nullptr); } +void FirstPartySetsHandlerImpl::ResetForTesting() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + enabled_ = absl::nullopt; + // base::Unretained(this) is safe here because this is a static singleton. + sets_loader_ = std::make_unique<FirstPartySetsLoader>(base::BindOnce( + &FirstPartySetsHandlerImpl::SetCompleteSets, base::Unretained(this))); + on_sets_ready_.Reset(); + persisted_sets_path_ = base::FilePath(); + sets_ = absl::nullopt; + raw_persisted_sets_ = absl::nullopt; +} + void FirstPartySetsHandlerImpl::SetManuallySpecifiedSet( const std::string& flag_value) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!IsFirstPartySetsEnabled()) + if (!IsEnabled()) return; sets_loader_->SetManuallySpecifiedSet(flag_value); } @@ -221,27 +243,7 @@ bool FirstPartySetsHandlerImpl::IsEnabledAndReady() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return IsFirstPartySetsEnabled() && sets_.has_value(); -} - -bool FirstPartySetsHandlerImpl::IsFirstPartySetsEnabled() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!enabled_.has_value()) { - enabled_ = GetContentClient()->browser()->IsFirstPartySetsEnabled(); - } - return enabled_.value(); -} - -void FirstPartySetsHandlerImpl::ResetForTesting() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - enabled_ = absl::nullopt; - // base::Unretained(this) is safe here because this is a static singleton. - sets_loader_ = std::make_unique<FirstPartySetsLoader>(base::BindOnce( - &FirstPartySetsHandlerImpl::SetCompleteSets, base::Unretained(this))); - on_sets_ready_.Reset(); - persisted_sets_path_ = base::FilePath(); - sets_ = absl::nullopt; - raw_persisted_sets_ = absl::nullopt; + return IsEnabled() && sets_.has_value(); } } // namespace content
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.h b/content/browser/first_party_sets/first_party_sets_handler_impl.h index a0f98fe..b713de7 100644 --- a/content/browser/first_party_sets/first_party_sets_handler_impl.h +++ b/content/browser/first_party_sets/first_party_sets_handler_impl.h
@@ -67,9 +67,11 @@ absl::optional<FlattenedSets> GetSetsIfEnabledAndReady(); // FirstPartySetsHandler + bool IsEnabled() override; void SetPublicFirstPartySets(base::File sets_file) override; absl::optional<PolicyParsingError> ValidateEnterprisePolicy( const base::Value::Dict& policy) const override; + void ResetForTesting() override; // Sets whether FPS is enabled (for testing). void SetEnabledForTesting(bool enabled) { @@ -88,18 +90,11 @@ const base::flat_map<net::SchemefulSite, net::SchemefulSite>& current_sets); - // Resets internal state for testing. - void ResetForTesting(); - private: friend class base::NoDestructor<FirstPartySetsHandlerImpl>; FirstPartySetsHandlerImpl(); - // This method checks whether First-Party Sets are enabled, and memoizes the - // returned value in `enabled_`. - bool IsFirstPartySetsEnabled(); - // This method reads the persisted First-Party Sets from the file under // `user_data_dir`. void SetPersistedSets(const base::FilePath& user_data_dir); @@ -149,8 +144,8 @@ // The path where persisted First-Party sets data is stored. base::FilePath persisted_sets_path_ GUARDED_BY_CONTEXT(sequence_checker_); - // This variable is used to memoize the value of IsFirstPartySetsEnabled() - // to avoid repeating unnecessary work. + // This variable is used to memoize the value of IsEnabled() to avoid + // repeating unnecessary work. absl::optional<bool> enabled_ GUARDED_BY_CONTEXT(sequence_checker_) = absl::nullopt;
diff --git a/content/browser/loader/cross_site_document_blocking_browsertest.cc b/content/browser/loader/cross_site_document_blocking_browsertest.cc index 27471a4..17a20a391 100644 --- a/content/browser/loader/cross_site_document_blocking_browsertest.cc +++ b/content/browser/loader/cross_site_document_blocking_browsertest.cc
@@ -1535,9 +1535,7 @@ // This test class sets up a link element for webbundle subresource loading. // e.g. <link rel=webbundle href=".../foo.wbn" resources="...">. -class CrossSiteDocumentBlockingWebBundleTest - : public ContentBrowserTest, - public testing::WithParamInterface<std::string> { +class CrossSiteDocumentBlockingWebBundleTest : public ContentBrowserTest { public: CrossSiteDocumentBlockingWebBundleTest() { scoped_feature_list_.InitAndEnableFeature(features::kSubresourceWebBundles); @@ -1551,11 +1549,6 @@ net::EmbeddedTestServer* https_server() { return &https_server_; } - static std::string DescribeParams( - const testing::TestParamInfo<ParamType>& info) { - return info.param; - } - protected: void SetupLinkWebBundleElementAndImgElement(const GURL& bundle_url, const GURL subresource_url) { @@ -1617,11 +1610,10 @@ // 1) cross-origin bundle, 2) same-origin bundle // X // A). CORB-protected MIME type (e.g. text/json), B) other type (e.g. image/png) -IN_PROC_BROWSER_TEST_P(CrossSiteDocumentBlockingWebBundleTest, +IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingWebBundleTest, CrossOriginWebBundleSubresoruceJson) { https_server()->StartAcceptingConnections(); - GURL bundle_url("https://cross-origin.test/web_bundle/cross_origin" + - GetParam() + ".wbn"); + GURL bundle_url("https://cross-origin.test/web_bundle/cross_origin_b2.wbn"); GURL subresource_url("https://cross-origin.test/web_bundle/resource.json"); RequestInterceptor interceptor(subresource_url); SetupLinkWebBundleElementAndImgElement(bundle_url, subresource_url); @@ -1632,11 +1624,10 @@ << "JSON in a cross-origin webbundle should be blocked by CORB"; } -IN_PROC_BROWSER_TEST_P(CrossSiteDocumentBlockingWebBundleTest, +IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingWebBundleTest, CrossOriginWebBundleSubresorucePng) { https_server()->StartAcceptingConnections(); - GURL bundle_url("https://cross-origin.test/web_bundle/cross_origin" + - GetParam() + ".wbn"); + GURL bundle_url("https://cross-origin.test/web_bundle/cross_origin_b2.wbn"); GURL subresource_url("https://cross-origin.test/web_bundle/resource.png"); RequestInterceptor interceptor(subresource_url); SetupLinkWebBundleElementAndImgElement(bundle_url, subresource_url); @@ -1647,11 +1638,10 @@ << "PNG in a cross-origin webbundle should not be blocked"; } -IN_PROC_BROWSER_TEST_P(CrossSiteDocumentBlockingWebBundleTest, +IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingWebBundleTest, SameOriginWebBundleSubresoruceJson) { https_server()->StartAcceptingConnections(); - GURL bundle_url("https://same-origin.test/web_bundle/same_origin" + - GetParam() + ".wbn"); + GURL bundle_url("https://same-origin.test/web_bundle/same_origin_b2.wbn"); GURL subresource_url("https://same-origin.test/web_bundle/resource.json"); RequestInterceptor interceptor(subresource_url); SetupLinkWebBundleElementAndImgElement(bundle_url, subresource_url); @@ -1662,11 +1652,10 @@ << "JSON in a same-origin webbundle should not be blocked"; } -IN_PROC_BROWSER_TEST_P(CrossSiteDocumentBlockingWebBundleTest, +IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingWebBundleTest, SameOriginWebBundleSubresorucePng) { https_server()->StartAcceptingConnections(); - GURL bundle_url("https://same-origin.test/web_bundle/same_origin" + - GetParam() + ".wbn"); + GURL bundle_url("https://same-origin.test/web_bundle/same_origin_b2.wbn"); GURL subresource_url("https://same-origin.test/web_bundle/resource.png"); RequestInterceptor interceptor(subresource_url); SetupLinkWebBundleElementAndImgElement(bundle_url, subresource_url); @@ -1677,10 +1666,4 @@ << "PNG in a same-origin webbundle should not be blocked"; } -INSTANTIATE_TEST_SUITE_P( - CrossSiteDocumentBlockingWebBundleTest, - CrossSiteDocumentBlockingWebBundleTest, - testing::Values("_b1", "_b2"), - CrossSiteDocumentBlockingWebBundleTest::DescribeParams); - } // namespace content
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 80b7b60..7a0e48d 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -977,11 +977,6 @@ const std::vector<network::mojom::WebClientHintsType>& accept_ch_frame, OnAcceptCHFrameReceivedCallback callback) { received_accept_ch_frame_ = true; - if (!base::FeatureList::IsEnabled(network::features::kAcceptCHFrame)) { - std::move(callback).Run(net::OK); - return; - } - LogAcceptCHFrameStatus(AcceptCHFrameRestart::kFramePresent); // Given that this is happening in the middle of navigation, there should
diff --git a/content/browser/renderer_host/media/media_resource_provider_fuchsia.cc b/content/browser/renderer_host/media/media_resource_provider_fuchsia.cc new file mode 100644 index 0000000..546981e --- /dev/null +++ b/content/browser/renderer_host/media/media_resource_provider_fuchsia.cc
@@ -0,0 +1,56 @@ +// Copyright 2022 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 "content/browser/renderer_host/media/media_resource_provider_fuchsia.h" + +#include "base/bind.h" +#include "base/fuchsia/process_context.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/provision_fetcher_factory.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/storage_partition.h" +#include "media/base/provision_fetcher.h" +#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h" + +namespace content { + +// static +void MediaResourceProviderFuchsia::Bind( + content::RenderFrameHost* frame_host, + mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider> + receiver) { + // The object will delete itself when connection to the frame is broken. + new MediaResourceProviderFuchsia(frame_host, std::move(receiver)); +} + +MediaResourceProviderFuchsia::MediaResourceProviderFuchsia( + content::RenderFrameHost* render_frame_host, + mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider> receiver) + : DocumentService(render_frame_host, std::move(receiver)) {} +MediaResourceProviderFuchsia::~MediaResourceProviderFuchsia() = default; + +void MediaResourceProviderFuchsia::CreateCdm( + const std::string& key_system, + fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> + request) { + auto* cdm_manager = media::FuchsiaCdmManager::GetInstance(); + if (!cdm_manager) { + DLOG(WARNING) << "FuchsiaCdmManager hasn't been initialized. Dropping " + "CreateCdm() request."; + return; + } + + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = + render_frame_host() + ->GetStoragePartition() + ->GetURLLoaderFactoryForBrowserProcess(); + + media::CreateFetcherCB create_fetcher_cb = base::BindRepeating( + &content::CreateProvisionFetcher, std::move(url_loader_factory)); + cdm_manager->CreateAndProvision( + key_system, origin(), std::move(create_fetcher_cb), std::move(request)); +} + +} // namespace content
diff --git a/content/browser/renderer_host/media/media_resource_provider_fuchsia.h b/content/browser/renderer_host/media/media_resource_provider_fuchsia.h new file mode 100644 index 0000000..dfcfe5e --- /dev/null +++ b/content/browser/renderer_host/media/media_resource_provider_fuchsia.h
@@ -0,0 +1,43 @@ +// Copyright 2022 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 CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_RESOURCE_PROVIDER_FUCHSIA_H_ +#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_RESOURCE_PROVIDER_FUCHSIA_H_ + +#include "content/public/browser/document_service.h" +#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h" + +namespace content { + +class MediaResourceProviderFuchsia final + : public content::DocumentService< + media::mojom::FuchsiaMediaResourceProvider> { + public: + ~MediaResourceProviderFuchsia() final; + + MediaResourceProviderFuchsia(const MediaResourceProviderFuchsia&) = delete; + MediaResourceProviderFuchsia& operator=(const MediaResourceProviderFuchsia&) = + delete; + + static void Bind( + content::RenderFrameHost* frame_host, + mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider> + receiver); + + private: + MediaResourceProviderFuchsia( + content::RenderFrameHost* render_frame_host, + mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider> + receiver); + + // media::mojom::FuchsiaMediaResourceProvider implementation. + void CreateCdm( + const std::string& key_system, + fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> + request) final; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_RESOURCE_PROVIDER_FUCHSIA_H_
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index e3da3ba..c831e3ce 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -37,9 +37,11 @@ #include "content/common/url_schemes.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_ui_url_loader_factory.h" #include "content/public/common/child_process_host.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" +#include "content/public/common/url_constants.h" #include "ipc/ipc_message.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/isolation_info.h" @@ -806,6 +808,16 @@ ContentBrowserClient::NonNetworkURLLoaderFactoryMap non_network_factories; non_network_factories[url::kDataScheme] = DataURLLoaderFactory::Create(); + if (base::FeatureList::IsEnabled( + features::kEnableServiceWorkersForChromeUntrusted)) { + if (origin.scheme() == content::kChromeUIUntrustedScheme) { + non_network_factories.emplace( + content::kChromeUIUntrustedScheme, + CreateWebUIServiceWorkerLoaderFactory( + rph->GetBrowserContext(), content::kChromeUIUntrustedScheme, + base::flat_set<std::string>())); + } + } GetContentClient() ->browser() ->RegisterNonNetworkSubresourceURLLoaderFactories(
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc index e5d31be..ccc39033 100644 --- a/content/browser/service_worker/service_worker_container_host.cc +++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -191,8 +191,20 @@ if (!service_worker_security_utils::AllOriginsMatchAndCanAccessServiceWorkers( urls)) { mojo::ReportBadMessage(ServiceWorkerConsts::kBadMessageImproperOrigins); - // ReportBadMessage() will kill the renderer process, but Mojo complains if - // the callback is not run. Just run it with nonsense arguments. + // ReportBadMessage() will terminate the renderer process, but Mojo + // complains if the callback is not run. Just run it with nonsense + // arguments. + std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown, + std::string(), nullptr); + return; + } + + if (!service_worker_security_utils:: + OriginCanRegisterServiceWorkerFromJavascript(url_)) { + mojo::ReportBadMessage(ServiceWorkerConsts::kBadMessageImproperOrigins); + // ReportBadMessage() will terminate the renderer process, but Mojo + // complains if the callback is not run. Just run it with nonsense + // arguments. std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown, std::string(), nullptr); return;
diff --git a/content/browser/service_worker/service_worker_container_host_unittest.cc b/content/browser/service_worker/service_worker_container_host_unittest.cc index 67e2ebce..4ea4e585 100644 --- a/content/browser/service_worker/service_worker_container_host_unittest.cc +++ b/content/browser/service_worker/service_worker_container_host_unittest.cc
@@ -948,6 +948,55 @@ EXPECT_EQ(3u, bad_messages_.size()); } +class WebUIServiceWorkerContainerHostTest + : public ServiceWorkerContainerHostTest, + public testing::WithParamInterface<bool> { + public: + WebUIServiceWorkerContainerHostTest() { + if (GetParam()) { + features_.InitAndEnableFeature( + features::kEnableServiceWorkersForChromeUntrusted); + } else { + features_.InitAndDisableFeature( + features::kEnableServiceWorkersForChromeUntrusted); + } + } + + private: + base::test::ScopedFeatureList features_; +}; + +TEST_P(WebUIServiceWorkerContainerHostTest, Register_RegistrationShouldFail) { + ServiceWorkerRemoteContainerEndpoint remote_endpoint = + PrepareServiceWorkerContainerHost(GURL("chrome://testwebui/")); + + ASSERT_TRUE(bad_messages_.empty()); + Register(remote_endpoint.host_remote()->get(), GURL("chrome://testwebui/"), + GURL("chrome://testwebui/sw.js")); + EXPECT_EQ(1u, bad_messages_.size()); +} + +TEST_P(WebUIServiceWorkerContainerHostTest, + Register_UntrustedRegistrationShouldFail) { + ServiceWorkerRemoteContainerEndpoint remote_endpoint = + PrepareServiceWorkerContainerHost(GURL("chrome-untrusted://testwebui/")); + + ASSERT_TRUE(bad_messages_.empty()); + Register(remote_endpoint.host_remote()->get(), + GURL("chrome-untrusted://testwebui/"), + GURL("chrome-untrusted://testwebui/sw.js")); + EXPECT_EQ(1u, bad_messages_.size()); +} + +INSTANTIATE_TEST_SUITE_P(All, + WebUIServiceWorkerContainerHostTest, + testing::Bool(), + [](const ::testing::TestParamInfo<bool>& info) { + if (info.param) + return "ServiceWorkersForChromeUntrustedEnabled"; + return "ServiceWorkersForChromeUntrustedDisabled"; + }); + TEST_F(ServiceWorkerContainerHostTest, EarlyContextDeletion) { ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index f1efcd6..f827745b 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -38,6 +38,7 @@ #include "content/browser/service_worker/service_worker_quota_client.h" #include "content/browser/service_worker/service_worker_version.h" #include "content/browser/storage_partition_impl.h" +#include "content/browser/webui/web_ui_controller_factory_registry.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -45,7 +46,12 @@ #include "content/public/browser/global_routing_id.h" #include "content/public/browser/service_worker_context_observer.h" #include "content/public/browser/storage_usage_info.h" +#include "content/public/browser/web_ui_url_loader_factory.h" +#include "content/public/browser/webui_config.h" +#include "content/public/browser/webui_config_map.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_features.h" +#include "content/public/common/url_constants.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/url_util.h" @@ -1535,6 +1541,8 @@ return nullptr; } + const url::Origin scope_origin = url::Origin::Create(scope); + mojo::PendingRemote<network::mojom::URLLoaderFactory> remote; mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver = remote.InitWithNewPipeAndPassReceiver(); @@ -1549,9 +1557,8 @@ storage_partition_->browser_context(), /*frame=*/nullptr, ChildProcessHost::kInvalidUniqueID, ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerScript, - url::Origin::Create(scope), /*navigation_id=*/absl::nullopt, - ukm::kInvalidSourceIdObj, &pending_receiver, &header_client, - &bypass_redirect_checks, + scope_origin, /*navigation_id=*/absl::nullopt, ukm::kInvalidSourceIdObj, + &pending_receiver, &header_client, &bypass_redirect_checks, /*disable_secure_dns=*/nullptr, /*factory_override=*/nullptr); @@ -1583,6 +1590,37 @@ std::unique_ptr<network::PendingSharedURLLoaderFactory> loader_factory_bundle_info = context()->loader_factory_bundle_for_update_check()->Clone(); + + if (base::FeatureList::IsEnabled( + features::kEnableServiceWorkersForChromeUntrusted) && + scope.scheme_piece() == kChromeUIUntrustedScheme) { + // If this is a Service Worker for a WebUI, the WebUI's URLDataSource needs + // to be registered. Registering a URLDataSource allows the + // WebUIURLLoaderFactory below to serve the resources for the WebUI. We + // register the URLDataSource here because the WebUI's resources are needed + // for the Service Worker update check to be performed which fetches the + // service worker script. + // + // This is similar to how we create a `WebUI` object in + // RenderFrameHostManager::GetFrameHostForNavigation(). Creating a `WebUI` + // also creates a `WebUIController` which register the URLDataSource for the + // WebUI which allows the navigation to be served correctly. We don't create + // a `WebUI` or a `WebUIController` for WebUI Service Workers so we + // register the URLDataSource directly. + if (auto* config = content::WebUIConfigMap::GetInstance().GetConfig( + browser_context(), scope_origin)) { + config->RegisterURLDataSource(browser_context()); + + static_cast<blink::PendingURLLoaderFactoryBundle*>( + loader_factory_bundle_info.get()) + ->pending_scheme_specific_factories() + .emplace(kChromeUIUntrustedScheme, + CreateWebUIServiceWorkerLoaderFactory( + browser_context(), kChromeUIUntrustedScheme, + base::flat_set<std::string>())); + } + } + static_cast<blink::PendingURLLoaderFactoryBundle*>( loader_factory_bundle_info.get()) ->pending_default_factory() = std::move(remote);
diff --git a/content/browser/service_worker/service_worker_security_utils.cc b/content/browser/service_worker/service_worker_security_utils.cc index fa6bbc1d..0be823b 100644 --- a/content/browser/service_worker/service_worker_security_utils.cc +++ b/content/browser/service_worker/service_worker_security_utils.cc
@@ -7,10 +7,19 @@ #include "base/command_line.h" #include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" +#include "content/public/common/url_constants.h" namespace content { namespace service_worker_security_utils { +bool OriginCanRegisterServiceWorkerFromJavascript(const GURL& url) { + // WebUI service workers are always registered in C++. + if (url.SchemeIs(kChromeUIUntrustedScheme)) + return false; + + return OriginCanAccessServiceWorkers(url); +} + bool AllOriginsMatchAndCanAccessServiceWorkers(const std::vector<GURL>& urls) { // (A) Check if all origins can access service worker. Every URL must be // checked despite the same-origin check below in (B), because GetOrigin()
diff --git a/content/browser/service_worker/service_worker_security_utils.h b/content/browser/service_worker/service_worker_security_utils.h index d824f94..5e3d499 100644 --- a/content/browser/service_worker/service_worker_security_utils.h +++ b/content/browser/service_worker/service_worker_security_utils.h
@@ -13,6 +13,11 @@ namespace content { namespace service_worker_security_utils { +// Returns true if |url| can register service workers from Javascript. This +// includes checking if |url| can access Service Workers. +CONTENT_EXPORT bool OriginCanRegisterServiceWorkerFromJavascript( + const GURL& url); + // Returns true if all members of |urls| have the same origin, and // OriginCanAccessServiceWorkers is true for this origin. // If --disable-web-security is enabled, the same origin check is
diff --git a/content/browser/web_contents/web_contents_view_mac_unittest.mm b/content/browser/web_contents/web_contents_view_mac_unittest.mm index 843333b0..ae32b59 100644 --- a/content/browser/web_contents/web_contents_view_mac_unittest.mm +++ b/content/browser/web_contents/web_contents_view_mac_unittest.mm
@@ -37,56 +37,4 @@ [view draggingSourceOperationMaskForLocal:NO]); } -namespace { - -class WebContentsViewMacTest : public RenderViewHostTestHarness { - public: - WebContentsViewMacTest(const WebContentsViewMacTest&) = delete; - WebContentsViewMacTest& operator=(const WebContentsViewMacTest&) = delete; - - protected: - WebContentsViewMacTest() = default; - - void SetUp() override { - RenderViewHostTestHarness::SetUp(); - window_.reset([[CocoaTestHelperWindow alloc] init]); - [[window_ contentView] - addSubview:web_contents()->GetNativeView().GetNativeNSView()]; - } - - base::scoped_nsobject<CocoaTestHelperWindow> window_; -}; - -} // namespace - -TEST_F(WebContentsViewMacTest, ShowHideParent) { - // A web contents that has never become visible starts off with a VISIBLE - // visibility state. Until it's made visible for the first time the flag - // `did_first_set_visible_` remains false, causing it to ignore all visibility - // state changes other than VISIBLE. This means if we don't order the window - // front before starting our test the web contents will report VISIBLE at all - // three checks. - [window_ orderFront:nil]; - EXPECT_EQ(content::Visibility::VISIBLE, web_contents()->GetVisibility()); - [[window_ contentView] setHidden:YES]; - EXPECT_EQ(content::Visibility::HIDDEN, web_contents()->GetVisibility()); - [[window_ contentView] setHidden:NO]; - EXPECT_EQ(content::Visibility::VISIBLE, web_contents()->GetVisibility()); -} - -TEST_F(WebContentsViewMacTest, OccludeView) { - // A web contents that has never become visible starts off with a VISIBLE - // visibility state. Until it's made visible for the first time the flag - // `did_first_set_visible_` remains false, causing it to ignore all visibility - // state changes other than VISIBLE. This means if we don't order the window - // front before starting our test the web contents will report VISIBLE at all - // three checks. - [window_ orderFront:nil]; - EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility()); - [window_ setPretendIsOccluded:YES]; - EXPECT_EQ(Visibility::OCCLUDED, web_contents()->GetVisibility()); - [window_ setPretendIsOccluded:NO]; - EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility()); -} - } // namespace content
diff --git a/content/browser/web_package/mock_web_bundle_reader_factory.cc b/content/browser/web_package/mock_web_bundle_reader_factory.cc index 62325c7..435e4d3 100644 --- a/content/browser/web_package/mock_web_bundle_reader_factory.cc +++ b/content/browser/web_package/mock_web_bundle_reader_factory.cc
@@ -222,8 +222,7 @@ base::test::TestFuture<web_package::mojom::BundleResponsePtr, web_package::mojom::BundleResponseParseErrorPtr> future; - reader->ReadResponse(resource_request, "" /* accept_langs */, - future.GetCallback()); + reader->ReadResponse(resource_request, future.GetCallback()); factory_->RunResponseCallback(std::move(expected_parse_args), std::move(response)); auto [bundle_response, error] = future.Take();
diff --git a/content/browser/web_package/web_bundle_browsertest_base.cc b/content/browser/web_package/web_bundle_browsertest_base.cc index ec31fa0a..90b8b0b 100644 --- a/content/browser/web_package/web_bundle_browsertest_base.cc +++ b/content/browser/web_package/web_bundle_browsertest_base.cc
@@ -117,12 +117,8 @@ int64_t response_body_file_size; EXPECT_TRUE(base::GetFileSize(response_body_file, &response_body_file_size)); for (const auto& url : urls) { - web_package::mojom::BundleIndexValuePtr item = - web_package::mojom::BundleIndexValue::New(); - item->response_locations.push_back( - web_package::mojom::BundleResponseLocation::New( - 0u, response_body_file_size)); - index_.insert({url, std::move(item)}); + index_.insert({url, web_package::mojom::BundleResponseLocation::New( + 0u, response_body_file_size)}); } in_process_data_decoder_.service().SetWebBundleParserFactoryBinderForTesting( base::BindRepeating(&MockParserFactory::BindWebBundleParserFactory, @@ -133,13 +129,9 @@ : primary_url_(items[0].first) { uint64_t offset = 0; for (const auto& item : items) { - web_package::mojom::BundleIndexValuePtr index_value = - web_package::mojom::BundleIndexValue::New(); - index_value->response_locations.push_back( - web_package::mojom::BundleResponseLocation::New(offset, - item.second.length())); + index_.insert({item.first, web_package::mojom::BundleResponseLocation::New( + offset, item.second.length())}); offset += item.second.length(); - index_.insert({item.first, std::move(index_value)}); } in_process_data_decoder_.service().SetWebBundleParserFactoryBinderForTesting( base::BindRepeating(&MockParserFactory::BindWebBundleParserFactory, @@ -154,7 +146,7 @@ return; } - base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> items; + base::flat_map<GURL, web_package::mojom::BundleResponseLocationPtr> items; for (const auto& item : index_) { items.insert({item.first, item.second.Clone()}); } @@ -230,12 +222,6 @@ bool TestBrowserClient::CanAcceptUntrustedExchangesIfNeeded() { return true; } -std::string TestBrowserClient::GetAcceptLangs(BrowserContext* context) { - return accept_langs_; -} -void TestBrowserClient::SetAcceptLangs(const std::string langs) { - accept_langs_ = langs; -} void WebBundleBrowserTestBase::SetUpOnMainThread() { ContentBrowserTest::SetUpOnMainThread(); @@ -247,10 +233,6 @@ SetBrowserClientForTesting(original_client_); } -void WebBundleBrowserTestBase::SetAcceptLangs(const std::string langs) { - browser_client_.SetAcceptLangs(langs); -} - void WebBundleBrowserTestBase::NavigateToBundleAndWaitForReady( const GURL& test_data_url, const GURL& expected_commit_url) {
diff --git a/content/browser/web_package/web_bundle_browsertest_base.h b/content/browser/web_package/web_bundle_browsertest_base.h index 05bd329..ad4e1745 100644 --- a/content/browser/web_package/web_bundle_browsertest_base.h +++ b/content/browser/web_package/web_bundle_browsertest_base.h
@@ -87,7 +87,8 @@ class MockParser final : public web_package::mojom::WebBundleParser { public: - using Index = base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr>; + using Index = + base::flat_map<GURL, web_package::mojom::BundleResponseLocationPtr>; MockParser( MockParserFactory* factory, @@ -157,7 +158,7 @@ bool simulate_parse_response_crash_ = false; std::unique_ptr<MockParser> parser_; int parser_creation_count_ = 0; - base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> index_; + base::flat_map<GURL, web_package::mojom::BundleResponseLocationPtr> index_; const GURL primary_url_; }; @@ -170,11 +171,6 @@ ~TestBrowserClient() override = default; bool CanAcceptUntrustedExchangesIfNeeded() override; - std::string GetAcceptLangs(BrowserContext* context) override; - void SetAcceptLangs(const std::string langs); - - private: - std::string accept_langs_ = "en"; }; class WebBundleBrowserTestBase : public ContentBrowserTest { @@ -190,8 +186,6 @@ void TearDownOnMainThread() override; - void SetAcceptLangs(const std::string langs); - void NavigateToBundleAndWaitForReady(const GURL& test_data_url, const GURL& expected_commit_url);
diff --git a/content/browser/web_package/web_bundle_file_browsertest.cc b/content/browser/web_package/web_bundle_file_browsertest.cc index ff77fb1..c7f37120 100644 --- a/content/browser/web_package/web_bundle_file_browsertest.cc +++ b/content/browser/web_package/web_bundle_file_browsertest.cc
@@ -63,74 +63,6 @@ test_data_url)); } - void RunNoLocalFileSchemeTest(std::string version_suffix) { - const GURL test_data_url = - GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath( - "web_bundle_browsertest_" + version_suffix + ".wbn")); - NavigateToBundleAndWaitForReady( - test_data_url, - web_bundle_utils::GetSynthesizedUrlForWebBundle( - test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl))); - - auto* expected_title = u"load failed"; - TitleWatcher title_watcher(shell()->web_contents(), expected_title); - title_watcher.AlsoWaitForTitle(u"Local Script"); - - const GURL script_file_url = net::FilePathToFileURL( - web_bundle_browsertest_utils::GetTestDataPath("local_script.js")); - const std::string script = - base::StringPrintf(R"( - const script = document.createElement("script"); - script.onerror = () => { document.title = "load failed";}; - script.src = "%s"; - document.body.appendChild(script);)", - script_file_url.spec().c_str()); - EXPECT_TRUE(ExecJs(shell()->web_contents(), script)); - - EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); - } - - void RunIframeNavigationNoCrashTest(std::string version_suffix) { - const GURL test_data_url = - GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath( - "web_bundle_browsertest_" + version_suffix + ".wbn")); - NavigateToBundleAndWaitForReady( - test_data_url, - web_bundle_utils::GetSynthesizedUrlForWebBundle( - test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl))); - - const std::string empty_page_path = "/web_bundle/empty_page.html"; - ASSERT_TRUE(embedded_test_server()->Start()); - const GURL empty_page_url = embedded_test_server()->GetURL(empty_page_path); - - ExecuteScriptAndWaitForTitle( - base::StringPrintf(R"( - (async function() { - const empty_page_url = '%s'; - const iframe = document.createElement('iframe'); - const onload = () => { - iframe.removeEventListener('load', onload); - document.title = 'Iframe loaded'; - } - iframe.addEventListener('load', onload); - iframe.src = empty_page_url; - document.body.appendChild(iframe); - })();)", - empty_page_url.spec().c_str()), - "Iframe loaded"); - - ExecuteScriptAndWaitForTitle(R"( - (async function() { - const iframe = document.querySelector("iframe"); - const onload = () => { - document.title = 'Iframe loaded again'; - } - iframe.addEventListener('load', onload); - iframe.src = iframe.src + '?'; - })();)", - "Iframe loaded again"); - } - private: base::test::ScopedFeatureList feature_list_; }; @@ -261,12 +193,30 @@ base::UTF16ToUTF8(console_observer.messages()[0].message)); } -IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, NoLocalFileSchemeB1) { - RunNoLocalFileSchemeTest("b2"); -} +IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, NoLocalFileScheme) { + const GURL test_data_url = + GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath( + "web_bundle_browsertest_b2.wbn")); + NavigateToBundleAndWaitForReady( + test_data_url, + web_bundle_utils::GetSynthesizedUrlForWebBundle( + test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl))); -IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, NoLocalFileSchemeB2) { - RunNoLocalFileSchemeTest("b1"); + auto* expected_title = u"load failed"; + TitleWatcher title_watcher(shell()->web_contents(), expected_title); + title_watcher.AlsoWaitForTitle(u"Local Script"); + + const GURL script_file_url = net::FilePathToFileURL( + web_bundle_browsertest_utils::GetTestDataPath("local_script.js")); + const std::string script = base::StringPrintf(R"( + const script = document.createElement("script"); + script.onerror = () => { document.title = "load failed";}; + script.src = "%s"; + document.body.appendChild(script);)", + script_file_url.spec().c_str()); + EXPECT_TRUE(ExecJs(shell()->web_contents(), script)); + + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); } IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, DataDecoderRestart) { @@ -352,73 +302,47 @@ console_message); } -IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, Variants) { - SetAcceptLangs("ja,en"); - const GURL test_data_url = GetTestUrlForFile( - web_bundle_browsertest_utils::GetTestDataPath("variants_test_b1.wbn")); - web_bundle_browsertest_utils::NavigateAndWaitForTitle( - shell()->web_contents(), test_data_url, - web_bundle_utils::GetSynthesizedUrlForWebBundle( - test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl)), - "lang=ja"); - SetAcceptLangs("en,ja"); - web_bundle_browsertest_utils::NavigateAndWaitForTitle( - shell()->web_contents(), test_data_url, - web_bundle_utils::GetSynthesizedUrlForWebBundle( - test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl)), - "lang=en"); - - ExecuteScriptAndWaitForTitle(R"( - (async function() { - const headers = {Accept: 'application/octet-stream'}; - const resp = await fetch('/type', {headers}); - const data = await resp.json(); - document.title = data.text; - })();)", - "octet-stream"); - ExecuteScriptAndWaitForTitle(R"( - (async function() { - const headers = {Accept: 'application/json'}; - const resp = await fetch('/type', {headers}); - const data = await resp.json(); - document.title = data.text; - })();)", - "json"); - ExecuteScriptAndWaitForTitle(R"( - (async function() { - const headers = {Accept: 'foo/bar'}; - const resp = await fetch('/type', {headers}); - const data = await resp.json(); - document.title = data.text; - })();)", - "octet-stream"); - - ExecuteScriptAndWaitForTitle(R"( - (async function() { - const resp = await fetch('/lang'); - const data = await resp.json(); - document.title = data.text; - })();)", - "ja"); - // If Accept-Language header is explicitly set, respect it. - ExecuteScriptAndWaitForTitle(R"( - (async function() { - const headers = {'Accept-Language': 'fr'}; - const resp = await fetch('/lang', {headers}); - const data = await resp.json(); - document.title = data.text; - })();)", - "fr"); -} - -IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeNavigationNoCrashB1) { +IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeNavigationNoCrash) { // Regression test for crbug.com/1058721. There was a bug that navigation of // OOPIF's remote iframe in Web Bundle file cause crash. - RunIframeNavigationNoCrashTest("b1"); -} + const GURL test_data_url = + GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath( + "web_bundle_browsertest_b2.wbn")); + NavigateToBundleAndWaitForReady( + test_data_url, + web_bundle_utils::GetSynthesizedUrlForWebBundle( + test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl))); -IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeNavigationNoCrashB2) { - RunIframeNavigationNoCrashTest("b2"); + const std::string empty_page_path = "/web_bundle/empty_page.html"; + ASSERT_TRUE(embedded_test_server()->Start()); + const GURL empty_page_url = embedded_test_server()->GetURL(empty_page_path); + + ExecuteScriptAndWaitForTitle( + base::StringPrintf(R"( + (async function() { + const empty_page_url = '%s'; + const iframe = document.createElement('iframe'); + const onload = () => { + iframe.removeEventListener('load', onload); + document.title = 'Iframe loaded'; + } + iframe.addEventListener('load', onload); + iframe.src = empty_page_url; + document.body.appendChild(iframe); + })();)", + empty_page_url.spec().c_str()), + "Iframe loaded"); + + ExecuteScriptAndWaitForTitle(R"( + (async function() { + const iframe = document.querySelector("iframe"); + const onload = () => { + document.title = 'Iframe loaded again'; + } + iframe.addEventListener('load', onload); + iframe.src = iframe.src + '?'; + })();)", + "Iframe loaded again"); } IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, Iframe) {
diff --git a/content/browser/web_package/web_bundle_reader.cc b/content/browser/web_package/web_bundle_reader.cc index 40bfcf2f..edbcea6 100644 --- a/content/browser/web_package/web_bundle_reader.cc +++ b/content/browser/web_package/web_bundle_reader.cc
@@ -182,13 +182,12 @@ void WebBundleReader::ReadResponse( const network::ResourceRequest& resource_request, - const std::string& accept_langs, ResponseCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_NE(state_, State::kInitial); auto it = entries_.find(net::SimplifyUrlForRequest(resource_request.url)); - if (it == entries_.end() || it->second->response_locations.empty()) { + if (it == entries_.end()) { base::ThreadPool::PostTask( FROM_HERE, base::BindOnce( @@ -198,28 +197,7 @@ "Not found in Web Bundle file."))); return; } - const web_package::mojom::BundleIndexValuePtr& entry = it->second; - - size_t response_index = 0; - if (!entry->variants_value.empty()) { - // Select the best variant for the request. - blink::WebPackageRequestMatcher matcher(resource_request.headers, - accept_langs); - auto found = matcher.FindBestMatchingIndex(entry->variants_value); - if (!found || *found >= entry->response_locations.size()) { - base::ThreadPool::PostTask( - FROM_HERE, - base::BindOnce( - std::move(callback), nullptr, - web_package::mojom::BundleResponseParseError::New( - web_package::mojom::BundleParseErrorType:: - kParserInternalError, - "Cannot find a response that matches request headers."))); - return; - } - response_index = *found; - } - auto response_location = entry->response_locations[response_index].Clone(); + auto response_location = it->second.Clone(); if (state_ == State::kDisconnected) { // Try reconnecting, if not attempted yet. @@ -359,7 +337,7 @@ std::move(callback), web_package::mojom::BundleMetadataParseError::New( web_package::mojom::BundleParseErrorType::kParserInternalError, - GURL() /* fallback_url */, base::File::ErrorToString(error)))); + base::File::ErrorToString(error)))); } else { parser_->ParseMetadata(base::BindOnce(&WebBundleReader::OnMetadataParsed, base::Unretained(this),
diff --git a/content/browser/web_package/web_bundle_reader.h b/content/browser/web_package/web_bundle_reader.h index 45d1c1e..c34ebd2c 100644 --- a/content/browser/web_package/web_bundle_reader.h +++ b/content/browser/web_package/web_bundle_reader.h
@@ -67,7 +67,6 @@ base::OnceCallback<void(web_package::mojom::BundleResponsePtr, web_package::mojom::BundleResponseParseErrorPtr)>; void ReadResponse(const network::ResourceRequest& resource_request, - const std::string& accept_langs, ResponseCallback callback); // Starts loading response body. |response| should be obtained by @@ -157,7 +156,7 @@ std::unique_ptr<WebBundleBlobDataSource> blob_data_source_; GURL primary_url_; - base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> entries_; + base::flat_map<GURL, web_package::mojom::BundleResponseLocationPtr> entries_; // Accumulates ReadResponse() requests while the parser is disconnected. std::vector<std::pair<web_package::mojom::BundleResponseLocationPtr, ResponseCallback>>
diff --git a/content/browser/web_package/web_bundle_reader_unittest.cc b/content/browser/web_package/web_bundle_reader_unittest.cc index 003056a..ece54fa 100644 --- a/content/browser/web_package/web_bundle_reader_unittest.cc +++ b/content/browser/web_package/web_bundle_reader_unittest.cc
@@ -37,15 +37,9 @@ } void ReadMetadata() { - base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> items; - web_package::mojom::BundleIndexValuePtr item = - web_package::mojom::BundleIndexValue::New(); - item->variants_value = "Accept;text/html;image/png"; - item->response_locations.push_back( - web_package::mojom::BundleResponseLocation::New(573u, 765u)); - item->response_locations.push_back( - web_package::mojom::BundleResponseLocation::New(333u, 222u)); - items.insert({primary_url_, std::move(item)}); + base::flat_map<GURL, web_package::mojom::BundleResponseLocationPtr> items; + items.insert({primary_url_, + web_package::mojom::BundleResponseLocation::New(573u, 765u)}); web_package::mojom::BundleMetadataPtr metadata = web_package::mojom::BundleMetadata::New(); @@ -172,36 +166,6 @@ })); } -TEST_F(WebBundleReaderTest, ReadResponseForSecondVariant) { - ReadMetadata(); - ASSERT_TRUE(GetReader()->HasEntry(GetPrimaryURL())); - - web_package::mojom::BundleResponsePtr response = - web_package::mojom::BundleResponse::New(); - response->response_code = 200; - response->payload_offset = 0xdead; - response->payload_length = 0xbeaf; - - network::ResourceRequest resource_request; - resource_request.url = GetPrimaryURL(); - resource_request.headers.SetHeader("Accept", "image/png"); - - GetMockFactory()->ReadAndFullfillResponse( - GetReader(), resource_request, - web_package::mojom::BundleResponseLocation::New(333u, 222u), - std::move(response), - base::BindOnce([](web_package::mojom::BundleResponsePtr response, - web_package::mojom::BundleResponseParseErrorPtr error) { - EXPECT_TRUE(response); - EXPECT_FALSE(error); - if (response) { - EXPECT_EQ(200, response->response_code); - EXPECT_EQ(0xdeadu, response->payload_offset); - EXPECT_EQ(0xbeafu, response->payload_length); - } - })); -} - TEST_F(WebBundleReaderTest, ReadResponseBody) { ReadMetadata();
diff --git a/content/browser/web_package/web_bundle_trustable_file_browsertest.cc b/content/browser/web_package/web_bundle_trustable_file_browsertest.cc index 0943cd1..82c986a 100644 --- a/content/browser/web_package/web_bundle_trustable_file_browsertest.cc +++ b/content/browser/web_package/web_bundle_trustable_file_browsertest.cc
@@ -92,14 +92,14 @@ contents.size()) > 0); } - void WriteCommonWebBundleFile(std::string version_suffix = "_b2") { + void WriteCommonWebBundleFile() { std::string contents; { base::ScopedAllowBlockingForTesting allow_blocking; - ASSERT_TRUE(base::ReadFileToString( - web_bundle_browsertest_utils::GetTestDataPath( - "web_bundle_browsertest" + version_suffix + ".wbn"), - &contents)); + ASSERT_TRUE( + base::ReadFileToString(web_bundle_browsertest_utils::GetTestDataPath( + "web_bundle_browsertest_b2.wbn"), + &contents)); } WriteWebBundleFile(contents); } @@ -144,14 +144,7 @@ }; IN_PROC_BROWSER_TEST_P(WebBundleTrustableFileBrowserTest, - TrustableWebBundleFileB1) { - WriteCommonWebBundleFile("_b1"); - NavigateToBundleAndWaitForReady( - test_data_url(), GURL(web_bundle_browsertest_utils::kTestPageUrl)); -} - -IN_PROC_BROWSER_TEST_P(WebBundleTrustableFileBrowserTest, - TrustableWebBundleFileB2) { + TrustableWebBundleFile) { WriteCommonWebBundleFile(); NavigateToBundleAndWaitForReady( test_data_url(), GURL(web_bundle_browsertest_utils::kTestPageUrl));
diff --git a/content/browser/web_package/web_bundle_url_loader_factory.cc b/content/browser/web_package/web_bundle_url_loader_factory.cc index d2d2394..d9e71a0 100644 --- a/content/browser/web_package/web_bundle_url_loader_factory.cc +++ b/content/browser/web_package/web_bundle_url_loader_factory.cc
@@ -15,10 +15,8 @@ #include "content/browser/web_package/web_bundle_reader.h" #include "content/browser/web_package/web_bundle_source.h" #include "content/browser/web_package/web_bundle_utils.h" -#include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_client.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/net_errors.h" #include "net/http/http_request_headers.h" @@ -61,9 +59,8 @@ } factory_->reader()->ReadResponse( - resource_request, GetAcceptLangs(), - base::BindOnce(&EntryLoader::OnResponseReady, - weak_factory_.GetWeakPtr())); + resource_request, base::BindOnce(&EntryLoader::OnResponseReady, + weak_factory_.GetWeakPtr())); } EntryLoader(const EntryLoader&) = delete; @@ -158,15 +155,6 @@ loader_client_->OnComplete(status); } - std::string GetAcceptLangs() const { - auto* web_contents = WebContents::FromFrameTreeNodeId(frame_tree_node_id_); - // This may be null if the WebContents has been closed, or in unit tests. - if (!web_contents) - return std::string(); - return GetContentClient()->browser()->GetAcceptLangs( - web_contents->GetBrowserContext()); - } - base::WeakPtr<WebBundleURLLoaderFactory> factory_; mojo::Remote<network::mojom::URLLoaderClient> loader_client_; const int frame_tree_node_id_;
diff --git a/content/browser/web_package/web_bundle_url_loader_factory_unittest.cc b/content/browser/web_package/web_bundle_url_loader_factory_unittest.cc index 93c08a0..276758c6 100644 --- a/content/browser/web_package/web_bundle_url_loader_factory_unittest.cc +++ b/content/browser/web_package/web_bundle_url_loader_factory_unittest.cc
@@ -42,12 +42,9 @@ loader_factory_ = std::make_unique<WebBundleURLLoaderFactory>( std::move(reader), FrameTreeNode::kFrameTreeNodeInvalidId); - base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> items; - web_package::mojom::BundleIndexValuePtr item = - web_package::mojom::BundleIndexValue::New(); - item->response_locations.push_back( - web_package::mojom::BundleResponseLocation::New(573u, 765u)); - items.insert({primary_url_, std::move(item)}); + base::flat_map<GURL, web_package::mojom::BundleResponseLocationPtr> items; + items.insert({primary_url_, + web_package::mojom::BundleResponseLocation::New(573u, 765u)}); web_package::mojom::BundleMetadataPtr metadata = web_package::mojom::BundleMetadata::New();
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc index 0106f239..26ea08b 100644 --- a/content/browser/webui/web_ui_url_loader_factory.cc +++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -250,8 +250,15 @@ // TODO: fill all the time related field i.e. request_time response_time // request_start response_start - WebContents::Getter wc_getter = - base::BindRepeating(WebContents::FromFrameTreeNodeId, frame_tree_node_id); + WebContents::Getter wc_getter; + + // Service Workers factories have no associated frame. + if (frame_tree_node_id == RenderFrameHost::kNoFrameTreeNodeId) { + wc_getter = base::BindRepeating([]() -> WebContents* { return nullptr; }); + } else { + wc_getter = base::BindRepeating(WebContents::FromFrameTreeNodeId, + frame_tree_node_id); + } bool replace_in_js = source->source()->ShouldReplaceI18nInJS() && @@ -283,7 +290,7 @@ // // |allowed_hosts| is an optional set of allowed host names. If empty then // all hosts are allowed. - static mojo::PendingRemote<network::mojom::URLLoaderFactory> Create( + static mojo::PendingRemote<network::mojom::URLLoaderFactory> CreateForFrame( FrameTreeNode* ftn, const std::string& scheme, base::flat_set<std::string> allowed_hosts) { @@ -292,9 +299,26 @@ // The WebUIURLLoaderFactory will delete itself when there are no more // receivers - see the // network::SelfDeletingURLLoaderFactory::OnDisconnect method. - new WebUIURLLoaderFactory(ftn, scheme, std::move(allowed_hosts), + new WebUIURLLoaderFactory(ftn->current_frame_host()->GetBrowserContext(), + ftn->frame_tree_node_id(), scheme, + std::move(allowed_hosts), pending_remote.InitWithNewPipeAndPassReceiver()); + return pending_remote; + } + static mojo::PendingRemote<network::mojom::URLLoaderFactory> + CreateForServiceWorker(BrowserContext* browser_context, + const std::string& scheme, + base::flat_set<std::string> allowed_hosts) { + mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote; + + // The WebUIURLLoaderFactory will delete itself when there are no more + // receivers - see the + // network::SelfDeletingURLLoaderFactory::OnDisconnect method. + new WebUIURLLoaderFactory(browser_context, + RenderFrameHost::kNoFrameTreeNodeId, scheme, + std::move(allowed_hosts), + pending_remote.InitWithNewPipeAndPassReceiver()); return pending_remote; } @@ -315,15 +339,12 @@ override { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* ftn = FrameTreeNode::GloballyFindByID(frame_tree_node_id_); - if (!ftn) { + if (frame_tree_node_id_ != RenderFrameHost::kNoFrameTreeNodeId && + !FrameTreeNode::GloballyFindByID(frame_tree_node_id_)) { CallOnError(std::move(client), net::ERR_FAILED); return; } - BrowserContext* browser_context = - ftn->current_frame_host()->GetBrowserContext(); - if (request.url.scheme() != scheme_) { DVLOG(1) << "Bad scheme: " << request.url.scheme(); SCOPED_CRASH_KEY_STRING32("WebUI", "actual_scheme", request.url.scheme()); @@ -353,7 +374,7 @@ base::BindOnce( &StartBlobInternalsURLLoader, request, std::move(client), base::Unretained( - ChromeBlobStorageContext::GetFor(browser_context)))); + ChromeBlobStorageContext::GetFor(browser_context_)))); return; } @@ -368,21 +389,24 @@ // navigation. The URLDataSources just need the WebContents; the specific // frame doesn't matter. StartURLLoader(request, frame_tree_node_id_, std::move(client), - browser_context); + browser_context_); } const std::string& scheme() const { return scheme_; } WebUIURLLoaderFactory( - FrameTreeNode* ftn, + BrowserContext* browser_context, + int frame_tree_node_id, const std::string& scheme, base::flat_set<std::string> allowed_hosts, mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver) : network::SelfDeletingURLLoaderFactory(std::move(factory_receiver)), - frame_tree_node_id_(ftn->frame_tree_node_id()), + browser_context_(browser_context), + frame_tree_node_id_(frame_tree_node_id), scheme_(scheme), allowed_hosts_(std::move(allowed_hosts)) {} + raw_ptr<BrowserContext> browser_context_; int const frame_tree_node_id_; const std::string scheme_; const base::flat_set<std::string> allowed_hosts_; // if empty all allowed. @@ -394,8 +418,17 @@ CreateWebUIURLLoaderFactory(RenderFrameHost* render_frame_host, const std::string& scheme, base::flat_set<std::string> allowed_hosts) { - return WebUIURLLoaderFactory::Create(FrameTreeNode::From(render_frame_host), - scheme, std::move(allowed_hosts)); + return WebUIURLLoaderFactory::CreateForFrame( + FrameTreeNode::From(render_frame_host), scheme, std::move(allowed_hosts)); +} + +mojo::PendingRemote<network::mojom::URLLoaderFactory> +CreateWebUIServiceWorkerLoaderFactory( + BrowserContext* browser_context, + const std::string& scheme, + base::flat_set<std::string> allowed_hosts) { + return WebUIURLLoaderFactory::CreateForServiceWorker( + browser_context, scheme, std::move(allowed_hosts)); } } // namespace content
diff --git a/content/common/url_schemes.cc b/content/common/url_schemes.cc index e594401..05423dde 100644 --- a/content/common/url_schemes.cc +++ b/content/common/url_schemes.cc
@@ -13,6 +13,7 @@ #include "base/strings/string_util.h" #include "build/build_config.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_features.h" #include "content/public/common/url_constants.h" #include "third_party/blink/public/common/scheme_registry.h" #include "url/url_util.h" @@ -104,6 +105,14 @@ url::EnableNonStandardSchemesForAndroidWebView(); #endif + // This should only be registered if the + // kEnableServiceWorkerForChromeUntrusted feature is enabled but checking + // it here causes a crash when --no-sandbox is enabled. See crbug.com/1313812 + // There are other render side checks and browser side checks that ensure + // service workers don't work for chrome-untrusted:// when the flag is not + // enabled. + schemes.service_worker_schemes.push_back(kChromeUIUntrustedScheme); + // Prevent future modification of the scheme lists. This is to prevent // accidental creation of data races in the program. Add*Scheme aren't // threadsafe so must be called when GURL isn't used on any other thread. This
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index d868351..4f1b2d3e 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -426,6 +426,10 @@ "webrtc_log.cc", "webrtc_log.h", "websocket_handshake_request_info.h", + "webui_config.cc", + "webui_config.h", + "webui_config_map.cc", + "webui_config_map.h", "worker_type.h", "zoom_level_delegate.h", ]
diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h index adcb48d..006246e0 100644 --- a/content/public/browser/first_party_sets_handler.h +++ b/content/public/browser/first_party_sets_handler.h
@@ -49,6 +49,11 @@ // Returns the singleton instance. static FirstPartySetsHandler* GetInstance(); + // Returns whether First-Party Sets is enabled. + // + // Embedders can use this method to guard First-Party Sets related changes. + virtual bool IsEnabled() = 0; + // Sets the First-Party Sets data from `sets_file` to initialize the // FirstPartySets instance. `sets_file` is expected to contain a sequence of // newline-delimited JSON records. Each record is a set declaration in the @@ -69,6 +74,9 @@ // will be used override First-Party Sets in those sources. virtual absl::optional<PolicyParsingError> ValidateEnterprisePolicy( const base::Value::Dict& policy) const = 0; + + // Resets the state on the instance for testing. + virtual void ResetForTesting() = 0; }; } // namespace content
diff --git a/content/public/browser/web_ui_url_loader_factory.h b/content/public/browser/web_ui_url_loader_factory.h index 419767f..cef47619 100644 --- a/content/public/browser/web_ui_url_loader_factory.h +++ b/content/public/browser/web_ui_url_loader_factory.h
@@ -14,7 +14,7 @@ namespace content { class RenderFrameHost; - +class BrowserContext; // Create and bind a URLLoaderFactory for loading resources matching the // specified |scheme| and also from a "pseudo host" matching one in // |allowed_hosts|. @@ -28,6 +28,12 @@ const std::string& scheme, base::flat_set<std::string> allowed_hosts); +CONTENT_EXPORT +mojo::PendingRemote<network::mojom::URLLoaderFactory> +CreateWebUIServiceWorkerLoaderFactory( + BrowserContext* browser_context, + const std::string& scheme, + base::flat_set<std::string> allowed_hosts); } // namespace content #endif // CONTENT_PUBLIC_BROWSER_WEB_UI_URL_LOADER_FACTORY_H_
diff --git a/ui/webui/webui_config.cc b/content/public/browser/webui_config.cc similarity index 67% rename from ui/webui/webui_config.cc rename to content/public/browser/webui_config.cc index a6da932..6416086 100644 --- a/ui/webui/webui_config.cc +++ b/content/public/browser/webui_config.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/webui/webui_config.h" +#include "content/public/browser/webui_config.h" -namespace ui { +namespace content { WebUIConfig::WebUIConfig(base::StringPiece scheme, base::StringPiece host) : scheme_(scheme), host_(host) {} WebUIConfig::~WebUIConfig() = default; -bool WebUIConfig::IsWebUIEnabled(content::BrowserContext* browser_context) { +bool WebUIConfig::IsWebUIEnabled(BrowserContext* browser_context) { return true; } -} // namespace ui +} // namespace content
diff --git a/content/public/browser/webui_config.h b/content/public/browser/webui_config.h new file mode 100644 index 0000000..ad8484cbe --- /dev/null +++ b/content/public/browser/webui_config.h
@@ -0,0 +1,69 @@ +// Copyright 2020 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 CONTENT_PUBLIC_BROWSER_WEBUI_CONFIG_H_ +#define CONTENT_PUBLIC_BROWSER_WEBUI_CONFIG_H_ + +#include <memory> +#include <string> + +#include "base/strings/string_piece.h" +#include "content/common/content_export.h" + +namespace content { + +class BrowserContext; +class WebUIController; +class WebUI; + +// Class that stores properties for a WebUI. +// +// Clients that implement WebUI pages subclass WebUIConfig, overload the +// relevant methods and add an instance of their subclass to WebUIConfigMap. +// +// WebUIConfig is used when navigating to chrome:// or chrome-untrusted:// +// pages to create the WebUIController and register the URLDataSource for +// the WebUI. +// +// WebUI pages are currently being migrated to use WebUIConfig so not +// all existing WebUI pages use this. +class CONTENT_EXPORT WebUIConfig { + public: + explicit WebUIConfig(base::StringPiece scheme, base::StringPiece host); + virtual ~WebUIConfig(); + WebUIConfig(const WebUIConfig&) = delete; + WebUIConfig& operator=(const WebUIConfig&) = delete; + + // Scheme for the WebUI. + const std::string& scheme() const { return scheme_; } + + // Host the WebUI serves. + const std::string& host() const { return host_; } + + // Returns whether the WebUI is enabled e.g. the necessary feature flags are + // on/off, the WebUI is enabled in incognito, etc. Defaults to true. + virtual bool IsWebUIEnabled(BrowserContext* browser_context); + + // Returns a WebUIController for the WebUI. + // + // URLDataSource is usually created in the constructor of WebUIController. The + // URLDataSource should be the same as the one registered in + // `RegisterURLDataSource()` or resources will fail to load. + virtual std::unique_ptr<WebUIController> CreateWebUIController( + WebUI* web_ui) = 0; + + // This is called when registering or updating a Service Worker. + // + // The URLDataSource here should be the same as the one registered in + // the WebUIController or resources will fail to load. + virtual void RegisterURLDataSource(BrowserContext* browser_context) {} + + private: + const std::string scheme_; + const std::string host_; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_WEBUI_CONFIG_H_
diff --git a/ui/webui/webui_config_map.cc b/content/public/browser/webui_config_map.cc similarity index 74% rename from ui/webui/webui_config_map.cc rename to content/public/browser/webui_config_map.cc index caca69e..4da3e8a 100644 --- a/ui/webui/webui_config_map.cc +++ b/content/public/browser/webui_config_map.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 "ui/webui/webui_config_map.h" +#include "content/public/browser/webui_config_map.h" #include "base/no_destructor.h" #include "base/strings/strcat.h" @@ -10,39 +10,38 @@ #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_controller.h" #include "content/public/browser/web_ui_controller_factory.h" +#include "content/public/browser/webui_config.h" #include "content/public/common/url_constants.h" -#include "ui/webui/webui_config.h" #include "url/gurl.h" -namespace ui { +namespace content { namespace { // Owned by WebUIConfigMap. Used to hook up with the existing WebUI infra. -class WebUIConfigMapWebUIControllerFactory - : public content::WebUIControllerFactory { +class WebUIConfigMapWebUIControllerFactory : public WebUIControllerFactory { public: explicit WebUIConfigMapWebUIControllerFactory(WebUIConfigMap& config_map) : config_map_(config_map) {} ~WebUIConfigMapWebUIControllerFactory() override = default; - content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context, - const GURL& url) override { + WebUI::TypeID GetWebUIType(BrowserContext* browser_context, + const GURL& url) override { auto* config = config_map_.GetConfig(browser_context, url::Origin::Create(url)); if (!config) - return content::WebUI::kNoWebUI; + return WebUI::kNoWebUI; - return reinterpret_cast<content::WebUI::TypeID>(config); + return reinterpret_cast<WebUI::TypeID>(config); } - bool UseWebUIForURL(content::BrowserContext* browser_context, + bool UseWebUIForURL(BrowserContext* browser_context, const GURL& url) override { return config_map_.GetConfig(browser_context, url::Origin::Create(url)); } - std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL( - content::WebUI* web_ui, + std::unique_ptr<WebUIController> CreateWebUIControllerForURL( + WebUI* web_ui, const GURL& url) override { auto* browser_context = web_ui->GetWebContents()->GetBrowserContext(); auto* config = @@ -69,20 +68,19 @@ WebUIConfigMap::WebUIConfigMap() : webui_controller_factory_( std::make_unique<WebUIConfigMapWebUIControllerFactory>(*this)) { - content::WebUIControllerFactory::RegisterFactory( - webui_controller_factory_.get()); + WebUIControllerFactory::RegisterFactory(webui_controller_factory_.get()); } WebUIConfigMap::~WebUIConfigMap() = default; void WebUIConfigMap::AddWebUIConfig(std::unique_ptr<WebUIConfig> config) { - CHECK_EQ(config->scheme(), content::kChromeUIScheme); + CHECK_EQ(config->scheme(), kChromeUIScheme); AddWebUIConfigImpl(std::move(config)); } void WebUIConfigMap::AddUntrustedWebUIConfig( std::unique_ptr<WebUIConfig> config) { - CHECK_EQ(config->scheme(), content::kChromeUIUntrustedScheme); + CHECK_EQ(config->scheme(), kChromeUIUntrustedScheme); AddWebUIConfigImpl(std::move(config)); } @@ -94,7 +92,7 @@ CHECK(it.second) << url; } -WebUIConfig* WebUIConfigMap::GetConfig(content::BrowserContext* browser_context, +WebUIConfig* WebUIConfigMap::GetConfig(BrowserContext* browser_context, const url::Origin& origin) { auto origin_and_config = configs_map_.find(origin); if (origin_and_config == configs_map_.end()) @@ -107,4 +105,4 @@ return config.get(); } -} // namespace ui +} // namespace content
diff --git a/ui/webui/webui_config_map.h b/content/public/browser/webui_config_map.h similarity index 79% rename from ui/webui/webui_config_map.h rename to content/public/browser/webui_config_map.h index 915e30fc..69f7420d 100644 --- a/ui/webui/webui_config_map.h +++ b/content/public/browser/webui_config_map.h
@@ -2,22 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_WEBUI_WEBUI_CONFIG_MAP_H_ -#define UI_WEBUI_WEBUI_CONFIG_MAP_H_ +#ifndef CONTENT_PUBLIC_BROWSER_WEBUI_CONFIG_MAP_H_ +#define CONTENT_PUBLIC_BROWSER_WEBUI_CONFIG_MAP_H_ #include <map> #include <memory> -namespace content { -class BrowserContext; -class WebUIControllerFactory; -} // namespace content +#include "content/common/content_export.h" namespace url { class Origin; } -namespace ui { +namespace content { + +class BrowserContext; +class WebUIControllerFactory; class WebUIConfig; // Class that holds all WebUIConfigs for the browser. @@ -27,7 +27,7 @@ // // Underneath it uses a WebUIControllerFactory to hook into the rest of the // WebUI infra. -class WebUIConfigMap { +class CONTENT_EXPORT WebUIConfigMap { public: static WebUIConfigMap& GetInstance(); @@ -50,19 +50,19 @@ // Returns the WebUIConfig for |origin| if it's registered and the WebUI is // enabled. (WebUIs can be disabled based on the profile or feature flags.) - WebUIConfig* GetConfig(content::BrowserContext* browser_context, + WebUIConfig* GetConfig(BrowserContext* browser_context, const url::Origin& origin); private: void AddWebUIConfigImpl(std::unique_ptr<WebUIConfig> config); using WebUIConfigMapImpl = - std::map<url::Origin, std::unique_ptr<ui::WebUIConfig>>; + std::map<url::Origin, std::unique_ptr<WebUIConfig>>; WebUIConfigMapImpl configs_map_; - std::unique_ptr<content::WebUIControllerFactory> webui_controller_factory_; + std::unique_ptr<WebUIControllerFactory> webui_controller_factory_; }; -} // namespace ui +} // namespace content -#endif // UI_WEBUI_WEBUI_CONFIG_MAP_H_ +#endif // CONTENT_PUBLIC_BROWSER_WEBUI_CONFIG_MAP_H_
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 7d5859fe..d6b2fbd 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -310,6 +310,11 @@ "EnableMachineLearningModelLoaderWebPlatformApi", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables service workers on chrome-untrusted:// urls. +const base::Feature kEnableServiceWorkersForChromeUntrusted{ + "EnableServiceWorkersForChromeUntrusted", + base::FEATURE_DISABLED_BY_DEFAULT}; + // If this feature is enabled and device permission is not granted by the user, // media-device enumeration will provide at most one device per type and the // device IDs will not be available.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 207d52e..cb3671b 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -81,6 +81,8 @@ CONTENT_EXPORT extern const base::Feature kEnableCanvas2DLayers; CONTENT_EXPORT extern const base::Feature kEnableMachineLearningModelLoaderWebPlatformApi; +CONTENT_EXPORT extern const base::Feature + kEnableServiceWorkersForChromeUntrusted; CONTENT_EXPORT extern const base::Feature kEnumerateDevicesHideDeviceIDs; CONTENT_EXPORT extern const base::Feature kExperimentalAccessibilityLabels; CONTENT_EXPORT extern const base::Feature
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 6ee1859..24b18a62 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -991,9 +991,16 @@ chrome_scheme); WebSecurityPolicy::RegisterURLSchemeAsWebUI(chrome_scheme); - // chrome-untrusted: WebString chrome_untrusted_scheme( WebString::FromASCII(kChromeUIUntrustedScheme)); + + // chrome-untrusted: + // Service workers for chrome-untrusted:// + if (base::FeatureList::IsEnabled( + features::kEnableServiceWorkersForChromeUntrusted)) { + WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers( + chrome_untrusted_scheme); + } WebSecurityPolicy::RegisterURLSchemeAsNotAllowingJavascriptURLs( chrome_untrusted_scheme); WebSecurityPolicy::RegisterURLSchemeAsSupportingFetchAPI(
diff --git a/content/test/data/attribution_reporting/page_with_conversion_redirect.html b/content/test/data/attribution_reporting/page_with_conversion_redirect.html index fde54c3a..657140a 100644 --- a/content/test/data/attribution_reporting/page_with_conversion_redirect.html +++ b/content/test/data/attribution_reporting/page_with_conversion_redirect.html
@@ -1,4 +1,7 @@ <html> - <script src="register_conversion.js"></script> + <head> + <script src="register_conversion.js"></script> + <script src="register_attribution_src.js"></script> + </head> This page has a script which creates images that redirect to the conversion registration endpoint. </html>
diff --git a/content/test/data/attribution_reporting/page_with_impression_creator.html b/content/test/data/attribution_reporting/page_with_impression_creator.html index ef27a40..dda1114 100644 --- a/content/test/data/attribution_reporting/page_with_impression_creator.html +++ b/content/test/data/attribution_reporting/page_with_impression_creator.html
@@ -1,6 +1,7 @@ <html> <head> <script src="register_impression.js"></script> + <script src="register_attribution_src.js"></script> </head> <body> This page has a script which creates anchor tags that declare impressions.
diff --git a/content/test/data/attribution_reporting/register_attribution_src.js b/content/test/data/attribution_reporting/register_attribution_src.js new file mode 100644 index 0000000..de3a565 --- /dev/null +++ b/content/test/data/attribution_reporting/register_attribution_src.js
@@ -0,0 +1,47 @@ +// Copyright 2022 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. + +function createAttributionSrcImg(src) { + const img = document.createElement('img'); + img.setAttribute('target', "top"); + img.width = 100; + img.height = 100; + img.setAttribute("attributionsrc", src); + document.body.appendChild(img); + return img; +} + +function createAttributionSrcAnchor({ + id, + url, + attributionsrc, + target = '_top', + left, + top, +} = {}) { + const anchor = document.createElement('a'); + anchor.href = url; + anchor.setAttribute('target', target); + anchor.setAttribute("attributionsrc", attributionsrc); + anchor.width = 100; + anchor.height = 100; + anchor.id = id; + + if (left !== undefined && top !== undefined) { + const style = 'position: absolute; left: ' + (left - 10) + + 'px; top: ' + (top - 10) + 'px; width: 20px; height: 20px;'; + anchor.setAttribute('style', style); + } + + anchor.innerText = 'This is link'; + + document.body.appendChild(anchor); + return anchor; +} + +function createAndClickAttributionSrcAnchor(params) { + const anchor = createAttributionSrcAnchor(params); + simulateClick(anchor); + return anchor; +}
diff --git a/content/test/data/attribution_reporting/register_impression.js b/content/test/data/attribution_reporting/register_impression.js index c12b80c..2f28c27 100644 --- a/content/test/data/attribution_reporting/register_impression.js +++ b/content/test/data/attribution_reporting/register_impression.js
@@ -66,47 +66,3 @@ simulateClick(anchor); return anchor; } - -function createAttributionSrcImg(src) { - const img = document.createElement('img'); - img.setAttribute('target', "top"); - img.width = 100; - img.height = 100; - img.setAttribute("attributionsrc", src); - document.body.appendChild(img); - return img; -} - -function createAttributionSrcAnchor({ - id, - url, - attributionsrc, - target = '_top', - left, - top, -} = {}) { - const anchor = document.createElement('a'); - anchor.href = url; - anchor.setAttribute('target', target); - anchor.setAttribute("attributionsrc", attributionsrc); - anchor.width = 100; - anchor.height = 100; - anchor.id = id; - - if (left !== undefined && top !== undefined) { - const style = 'position: absolute; left: ' + (left - 10) + - 'px; top: ' + (top - 10) + 'px; width: 20px; height: 20px;'; - anchor.setAttribute('style', style); - } - - anchor.innerText = 'This is link'; - - document.body.appendChild(anchor); - return anchor; -} - -function createAndClickAttributionSrcAnchor(params) { - const anchor = createAttributionSrcAnchor(params); - simulateClick(anchor); - return anchor; -}
diff --git a/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers b/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers index a1ddf2c4..924ce5a 100644 --- a/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers +++ b/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers
@@ -1,2 +1,2 @@ HTTP/1.1 200 OK -Attribution-Reporting-Register-Event-Trigger:[{"trigger_data": "10"}] \ No newline at end of file +Attribution-Reporting-Register-Event-Trigger:[{"trigger_data": "7"}] \ No newline at end of file
diff --git a/content/test/data/attribution_reporting/register_trigger_headers_dedup.html b/content/test/data/attribution_reporting/register_trigger_headers_dedup.html new file mode 100644 index 0000000..b56e1988 --- /dev/null +++ b/content/test/data/attribution_reporting/register_trigger_headers_dedup.html
@@ -0,0 +1 @@ +Registers a trigger with a dedup key.
diff --git a/content/test/data/attribution_reporting/register_trigger_headers_dedup.html.mock-http-headers b/content/test/data/attribution_reporting/register_trigger_headers_dedup.html.mock-http-headers new file mode 100644 index 0000000..ec4cd06 --- /dev/null +++ b/content/test/data/attribution_reporting/register_trigger_headers_dedup.html.mock-http-headers
@@ -0,0 +1,2 @@ +HTTP/1.1 200 OK +Attribution-Reporting-Register-Event-Trigger:[{"trigger_data": "1", "deduplication_key":"123"}] \ No newline at end of file
diff --git a/content/test/data/web_bundle/cross_origin_b1.wbn b/content/test/data/web_bundle/cross_origin_b1.wbn deleted file mode 100644 index 35fb24db..0000000 --- a/content/test/data/web_bundle/cross_origin_b1.wbn +++ /dev/null Binary files differ
diff --git a/content/test/data/web_bundle/cross_origin_b1.wbn.mock-http-headers b/content/test/data/web_bundle/cross_origin_b1.wbn.mock-http-headers deleted file mode 100644 index f41b781..0000000 --- a/content/test/data/web_bundle/cross_origin_b1.wbn.mock-http-headers +++ /dev/null
@@ -1,4 +0,0 @@ -HTTP/1.1 200 OK -Content-Type: application/webbundle -X-Content-Type-Options: nosniff -Access-Control-Allow-Origin: *
diff --git a/content/test/data/web_bundle/generate-test-wbns.sh b/content/test/data/web_bundle/generate-test-wbns.sh index 0242db6..609e7a5 100755 --- a/content/test/data/web_bundle/generate-test-wbns.sh +++ b/content/test/data/web_bundle/generate-test-wbns.sh
@@ -20,13 +20,6 @@ -dir web_bundle_browsertest/ \ -o web_bundle_browsertest_b2.wbn -gen-bundle \ - -version b1 \ - -baseURL https://test.example.org/ \ - -primaryURL https://test.example.org/ \ - -dir web_bundle_browsertest/ \ - -o web_bundle_browsertest_b1.wbn - # Generate a base WBN which will used to generate broken WBN. # This WBN must contains 3 entries: # [1]: https://test.example.org/ @@ -53,26 +46,6 @@ sed 's/3a737461747573/3a787878787878/3' | xxd -r -p > broken_bundle_broken_script_entry_b2.wbn -gen-bundle \ - -version b1 \ - -primaryURL https://test.example.org/ \ - -har variants_test.har \ - -o variants_test_b1.wbn - -# Generate a WBN which will be used as a cross origin bundle. -gen-bundle \ - -version b1 \ - -har cross_origin.har \ - -primaryURL https://cross-origin.test/web_bundle/resource.json \ - -o cross_origin_b1.wbn - -# Generate a WBN which will be used as a same origin bundle. -gen-bundle \ - -version b1 \ - -har same_origin.har \ - -primaryURL https://same-origin.test/web_bundle/resource.json \ - -o same_origin_b1.wbn - # Generate a WBN which will be used as a cross origin bundle. gen-bundle \ -version b2 \
diff --git a/content/test/data/web_bundle/same_origin_b1.wbn b/content/test/data/web_bundle/same_origin_b1.wbn deleted file mode 100644 index 0960a20..0000000 --- a/content/test/data/web_bundle/same_origin_b1.wbn +++ /dev/null Binary files differ
diff --git a/content/test/data/web_bundle/same_origin_b1.wbn.mock-http-headers b/content/test/data/web_bundle/same_origin_b1.wbn.mock-http-headers deleted file mode 100644 index de859fc..0000000 --- a/content/test/data/web_bundle/same_origin_b1.wbn.mock-http-headers +++ /dev/null
@@ -1,3 +0,0 @@ -HTTP/1.1 200 OK -Content-Type: application/webbundle -X-Content-Type-Options: nosniff
diff --git a/content/test/data/web_bundle/variants_test.har b/content/test/data/web_bundle/variants_test.har deleted file mode 100644 index df8139a..0000000 --- a/content/test/data/web_bundle/variants_test.har +++ /dev/null
@@ -1,187 +0,0 @@ -{ - "log": { - "version": "1.2", - "entries": [ - { - "request": { - "method": "GET", - "url": "https://test.example.org/" - }, - "response": { - "status": 200, - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=UTF-8" - }, - { - "name": "Content-Language", - "value": "en" - }, - { - "name": "Variants", - "value": "Accept-Language;en;ja" - }, - { - "name": "Variant-Key", - "value": "en" - } - ], - "content": { - "text": "<title>lang=en</title>" - } - } - }, - { - "request": { - "method": "GET", - "url": "https://test.example.org/" - }, - "response": { - "status": 200, - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=UTF-8" - }, - { - "name": "Content-Language", - "value": "ja" - }, - { - "name": "Variants", - "value": "Accept-Language;en;ja" - }, - { - "name": "Variant-Key", - "value": "ja" - } - ], - "content": { - "text": "<title>lang=ja</title>" - } - } - }, - { - "request": { - "method": "GET", - "url": "https://test.example.org/type" - }, - "response": { - "status": 200, - "headers": [ - { - "name": "Content-Type", - "value": "application/octet-stream" - }, - { - "name": "Access-Control-Allow-Origin", - "value": "*" - }, - { - "name": "Variants", - "value": "Accept;application/octet-stream;application/json" - }, - { - "name": "Variant-Key", - "value": "application/octet-stream" - } - ], - "content": { - "text": "{\"text\":\"octet-stream\"}" - } - } - }, - { - "request": { - "method": "GET", - "url": "https://test.example.org/type" - }, - "response": { - "status": 200, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "Access-Control-Allow-Origin", - "value": "*" - }, - { - "name": "Variants", - "value": "Accept;application/octet-stream;application/json" - }, - { - "name": "Variant-Key", - "value": "application/json" - } - ], - "content": { - "text": "{\"text\":\"json\"}" - } - } - }, - { - "request": { - "method": "GET", - "url": "https://test.example.org/lang" - }, - "response": { - "status": 200, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "Access-Control-Allow-Origin", - "value": "*" - }, - { - "name": "Variants", - "value": "Accept-Language;fr;ja" - }, - { - "name": "Variant-Key", - "value": "fr" - } - ], - "content": { - "text": "{\"text\":\"fr\"}" - } - } - }, - { - "request": { - "method": "GET", - "url": "https://test.example.org/lang" - }, - "response": { - "status": 200, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "Access-Control-Allow-Origin", - "value": "*" - }, - { - "name": "Variants", - "value": "Accept-Language;fr;ja" - }, - { - "name": "Variant-Key", - "value": "ja" - } - ], - "content": { - "text": "{\"text\":\"ja\"}" - } - } - } - ] - } -}
diff --git a/content/test/data/web_bundle/variants_test_b1.wbn b/content/test/data/web_bundle/variants_test_b1.wbn deleted file mode 100644 index 114f6899..0000000 --- a/content/test/data/web_bundle/variants_test_b1.wbn +++ /dev/null Binary files differ
diff --git a/content/test/data/web_bundle/variants_test_b1.wbn.mock-http-headers b/content/test/data/web_bundle/variants_test_b1.wbn.mock-http-headers deleted file mode 100644 index de859fc..0000000 --- a/content/test/data/web_bundle/variants_test_b1.wbn.mock-http-headers +++ /dev/null
@@ -1,3 +0,0 @@ -HTTP/1.1 200 OK -Content-Type: application/webbundle -X-Content-Type-Options: nosniff
diff --git a/content/test/data/web_bundle/web_bundle_browsertest_b1.wbn b/content/test/data/web_bundle/web_bundle_browsertest_b1.wbn deleted file mode 100644 index 45e5936..0000000 --- a/content/test/data/web_bundle/web_bundle_browsertest_b1.wbn +++ /dev/null Binary files differ
diff --git a/content/test/data/web_bundle/web_bundle_browsertest_b1.wbn.mock-http-headers b/content/test/data/web_bundle/web_bundle_browsertest_b1.wbn.mock-http-headers deleted file mode 100644 index de859fc..0000000 --- a/content/test/data/web_bundle/web_bundle_browsertest_b1.wbn.mock-http-headers +++ /dev/null
@@ -1,3 +0,0 @@ -HTTP/1.1 200 OK -Content-Type: application/webbundle -X-Content-Type-Options: nosniff
diff --git a/device/bluetooth/bluetooth_strings.grd b/device/bluetooth/bluetooth_strings.grd index 2ae6ad7..68304f0 100644 --- a/device/bluetooth/bluetooth_strings.grd +++ b/device/bluetooth/bluetooth_strings.grd
@@ -21,6 +21,7 @@ <output filename="bluetooth_strings_bs.pak" type="data_package" lang="bs" /> <output filename="bluetooth_strings_ca.pak" type="data_package" lang="ca" /> <output filename="bluetooth_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="bluetooth_strings_cy.pak" type="data_package" lang="cy" /> <output filename="bluetooth_strings_da.pak" type="data_package" lang="da" /> <output filename="bluetooth_strings_de.pak" type="data_package" lang="de" /> <output filename="bluetooth_strings_el.pak" type="data_package" lang="el" />
diff --git a/device/fido/fido_strings.grd b/device/fido/fido_strings.grd index 4fee5a88..13c8462 100644 --- a/device/fido/fido_strings.grd +++ b/device/fido/fido_strings.grd
@@ -21,6 +21,7 @@ <output filename="fido_strings_bs.pak" type="data_package" lang="bs" /> <output filename="fido_strings_ca.pak" type="data_package" lang="ca" /> <output filename="fido_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="fido_strings_cy.pak" type="data_package" lang="cy" /> <output filename="fido_strings_da.pak" type="data_package" lang="da" /> <output filename="fido_strings_de.pak" type="data_package" lang="de" /> <output filename="fido_strings_el.pak" type="data_package" lang="el" />
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index ad5427d..9367509 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json
@@ -336,6 +336,7 @@ "chrome://history/*", "chrome://new-tab-page/*", "chrome://os-settings/*", + "chrome://personalization/*", "chrome://profile-picker/*", "chrome://read-later.top-chrome/*", "chrome://settings/*",
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc index 19dc461..6922ff3 100644 --- a/extensions/common/extension.cc +++ b/extensions/common/extension.cc
@@ -14,7 +14,6 @@ #include "base/base64.h" #include "base/command_line.h" -#include "base/feature_list.h" #include "base/files/file_path.h" #include "base/i18n/rtl.h" #include "base/json/json_writer.h" @@ -31,8 +30,6 @@ #include "content/public/common/url_constants.h" #include "extensions/common/constants.h" #include "extensions/common/error_utils.h" -#include "extensions/common/extension_features.h" -#include "extensions/common/feature_switch.h" #include "extensions/common/manifest.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_handler.h" @@ -90,14 +87,6 @@ ManifestLocation location, int creation_flags, std::string* warning) { - // The ultimate short-circuit: If the feature for MV3 is disabled, it's not - // supported. - if (manifest_version == 3 && - !base::FeatureList::IsEnabled( - extensions_features::kMv3ExtensionsSupported)) { - return false; - } - // Supported versions are always safe. if (manifest_version >= kMinimumSupportedManifestVersion && manifest_version <= kMaximumSupportedManifestVersion) {
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index 5084366..0f7963f 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -36,10 +36,6 @@ const base::Feature kContentScriptsMatchOriginAsFallback{ "ContentScriptsMatchOriginAsFallback", base::FEATURE_ENABLED_BY_DEFAULT}; -// Whether Manifest Version 3-based extensions are supported. -const base::Feature kMv3ExtensionsSupported{"Mv3ExtensionsSupported", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Reports Extensions.WebRequest.KeepaliveRequestFinished when enabled. const base::Feature kReportKeepaliveUkm{"ReportKeepaliveUkm", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h index d20cd1f6e..2261d80e 100644 --- a/extensions/common/extension_features.h +++ b/extensions/common/extension_features.h
@@ -18,8 +18,6 @@ extern const base::Feature kContentScriptsMatchOriginAsFallback; -extern const base::Feature kMv3ExtensionsSupported; - extern const base::Feature kReportKeepaliveUkm; extern const base::Feature kAllowSharedArrayBuffersUnconditionally;
diff --git a/extensions/common/extension_unittest.cc b/extensions/common/extension_unittest.cc index 4b037eb..800e2a5 100644 --- a/extensions/common/extension_unittest.cc +++ b/extensions/common/extension_unittest.cc
@@ -148,15 +148,6 @@ EXPECT_TRUE( RunManifestVersionSuccess(get_manifest(absl::nullopt), kType, 1)); } - - { - // If the requisite feature is disabled, Manifest V3 extensions should - // fail to load. - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - extensions_features::kMv3ExtensionsSupported); - EXPECT_TRUE(RunManifestVersionFailure(get_manifest(3))); - } } TEST(ExtensionTest, PlatformAppManifestVersions) {
diff --git a/extensions/strings/extensions_strings.grd b/extensions/strings/extensions_strings.grd index e13577d6..cade0c1 100644 --- a/extensions/strings/extensions_strings.grd +++ b/extensions/strings/extensions_strings.grd
@@ -23,6 +23,7 @@ <output filename="extensions_strings_bs.pak" type="data_package" lang="bs" /> <output filename="extensions_strings_ca.pak" type="data_package" lang="ca" /> <output filename="extensions_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="extensions_strings_cy.pak" type="data_package" lang="cy" /> <output filename="extensions_strings_da.pak" type="data_package" lang="da" /> <output filename="extensions_strings_de.pak" type="data_package" lang="de" /> <output filename="extensions_strings_el.pak" type="data_package" lang="el" />
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn index 602a36c..b789fa7 100644 --- a/fuchsia/engine/BUILD.gn +++ b/fuchsia/engine/BUILD.gn
@@ -129,7 +129,6 @@ "//gpu/command_buffer/service", "//media", "//media/fuchsia/cdm/service", - "//media/fuchsia/mojom:cdm_provider", "//media/mojo/common", "//media/mojo/services", "//mojo/public/cpp/bindings", @@ -221,8 +220,6 @@ "browser/accessibility_bridge.h", "browser/ax_tree_converter.cc", "browser/ax_tree_converter.h", - "browser/cdm_provider_service.cc", - "browser/cdm_provider_service.h", "browser/content_directory_loader_factory.cc", "browser/content_directory_loader_factory.h", "browser/context_impl.cc",
diff --git a/fuchsia/engine/browser/cdm_provider_service.cc b/fuchsia/engine/browser/cdm_provider_service.cc deleted file mode 100644 index 1c25cb4..0000000 --- a/fuchsia/engine/browser/cdm_provider_service.cc +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright 2020 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 "fuchsia/engine/browser/cdm_provider_service.h" - -#include <lib/fidl/cpp/interface_handle.h> -#include <lib/sys/cpp/component_context.h> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/fuchsia/process_context.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/document_service.h" -#include "content/public/browser/provision_fetcher_factory.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/storage_partition.h" -#include "fuchsia/engine/switches.h" -#include "media/base/provision_fetcher.h" -#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h" -#include "third_party/widevine/cdm/widevine_cdm_common.h" - -namespace { - -class CdmProviderImpl final - : public content::DocumentService<media::mojom::FuchsiaCdmProvider> { - public: - CdmProviderImpl( - media::FuchsiaCdmManager* cdm_manager, - content::RenderFrameHost* render_frame_host, - mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver); - ~CdmProviderImpl() override; - - CdmProviderImpl(const CdmProviderImpl&) = delete; - CdmProviderImpl& operator=(const CdmProviderImpl&) = delete; - - // media::mojom::FuchsiaCdmProvider implementation. - void CreateCdm( - const std::string& key_system, - fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> - request) override; - - private: - media::FuchsiaCdmManager* const cdm_manager_; -}; - -CdmProviderImpl::CdmProviderImpl( - media::FuchsiaCdmManager* cdm_manager, - content::RenderFrameHost* render_frame_host, - mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver) - : DocumentService(render_frame_host, std::move(receiver)), - cdm_manager_(cdm_manager) { - DCHECK(cdm_manager_); -} - -CdmProviderImpl::~CdmProviderImpl() = default; - -void CdmProviderImpl::CreateCdm( - const std::string& key_system, - fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> - request) { - scoped_refptr<network::SharedURLLoaderFactory> loader_factory = - render_frame_host() - ->GetProcess() - ->GetBrowserContext() - ->GetDefaultStoragePartition() - ->GetURLLoaderFactoryForBrowserProcess(); - media::CreateFetcherCB create_fetcher_cb = base::BindRepeating( - &content::CreateProvisionFetcher, std::move(loader_factory)); - cdm_manager_->CreateAndProvision( - key_system, origin(), std::move(create_fetcher_cb), std::move(request)); -} - -template <typename KeySystemInterface> -fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> ConnectToKeySystem() { - static_assert( - (std::is_same<KeySystemInterface, fuchsia::media::drm::Widevine>::value || - std::is_same<KeySystemInterface, fuchsia::media::drm::PlayReady>::value), - "KeySystemInterface must be either fuchsia::media::drm::Widevine or " - "fuchsia::media::drm::PlayReady"); - - // TODO(fxbug.dev/13674): Once the key system specific protocols are turned - // into services, we should not need to manually force the key system specific - // interface into the KeySystem interface. - fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> key_system; - base::ComponentContextForProcess()->svc()->Connect(key_system.NewRequest(), - KeySystemInterface::Name_); - return key_system; -} - -std::unique_ptr<media::FuchsiaCdmManager> CreateCdmManager() { - media::FuchsiaCdmManager::CreateKeySystemCallbackMap - create_key_system_callbacks; - - const auto* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kEnableWidevine)) { - create_key_system_callbacks.emplace( - kWidevineKeySystem, - base::BindRepeating( - &ConnectToKeySystem<fuchsia::media::drm::Widevine>)); - } - - std::string playready_key_system = - command_line->GetSwitchValueASCII(switches::kPlayreadyKeySystem); - if (!playready_key_system.empty()) { - create_key_system_callbacks.emplace( - playready_key_system, - base::BindRepeating( - &ConnectToKeySystem<fuchsia::media::drm::PlayReady>)); - } - - std::string cdm_data_directory = - command_line->GetSwitchValueASCII(switches::kCdmDataDirectory); - - absl::optional<uint64_t> cdm_data_quota_bytes; - if (command_line->HasSwitch(switches::kCdmDataQuotaBytes)) { - uint64_t value = 0; - CHECK(base::StringToUint64( - command_line->GetSwitchValueASCII(switches::kCdmDataQuotaBytes), - &value)); - cdm_data_quota_bytes = value; - } - - return std::make_unique<media::FuchsiaCdmManager>( - std::move(create_key_system_callbacks), - base::FilePath(cdm_data_directory), cdm_data_quota_bytes); -} - -} // namespace - -CdmProviderService::CdmProviderService() : cdm_manager_(CreateCdmManager()) {} - -CdmProviderService::~CdmProviderService() = default; - -void CdmProviderService::Bind( - content::RenderFrameHost* frame_host, - mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver) { - // The object will delete itself when connection to the frame is broken. - new CdmProviderImpl(cdm_manager_.get(), frame_host, std::move(receiver)); -}
diff --git a/fuchsia/engine/browser/cdm_provider_service.h b/fuchsia/engine/browser/cdm_provider_service.h deleted file mode 100644 index 103693b..0000000 --- a/fuchsia/engine/browser/cdm_provider_service.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2020 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 FUCHSIA_ENGINE_BROWSER_CDM_PROVIDER_SERVICE_H_ -#define FUCHSIA_ENGINE_BROWSER_CDM_PROVIDER_SERVICE_H_ - -#include "media/fuchsia/mojom/fuchsia_cdm_provider.mojom.h" - -namespace content { -class RenderFrameHost; -} // namespace content - -namespace media { -class FuchsiaCdmManager; -} // namespace media - -class CdmProviderService { - public: - CdmProviderService(); - ~CdmProviderService(); - - CdmProviderService(const CdmProviderService&) = delete; - CdmProviderService& operator=(const CdmProviderService&) = delete; - - void Bind(content::RenderFrameHost* frame_host, - mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver); - - private: - std::unique_ptr<media::FuchsiaCdmManager> cdm_manager_; -}; - -#endif // FUCHSIA_ENGINE_BROWSER_CDM_PROVIDER_SERVICE_H_
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc index c8133e6..03f23d6 100644 --- a/fuchsia/engine/browser/frame_impl_browsertest.cc +++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -106,15 +106,9 @@ // Verifies that Frames are initially "hidden", changes to "visible" once the // View is attached to a Presenter and back to "hidden" when the View is // detached from the Presenter. -// TODO(crbug.com/1058247): Re-enable this test on Arm64 when femu is available -// for that architecture. This test requires Vulkan and Scenic to properly -// signal the Views visibility. -#if defined(ARCH_CPU_ARM_FAMILY) -#define MAYBE_VisibilityState DISABLED_VisibilityState -#else -#define MAYBE_VisibilityState VisibilityState -#endif -IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_VisibilityState) { +// TODO(https://crbug.com/1314086): Re-enable this test when we can make it work +// with the fake hardware display controller provider used for tests. +IN_PROC_BROWSER_TEST_F(FrameImplTest, DISABLED_VisibilityState) { net::test_server::EmbeddedTestServerHandle test_server_handle; ASSERT_TRUE(test_server_handle = embedded_test_server()->StartAndReturnHandle());
diff --git a/fuchsia/engine/browser/web_engine_browser_interface_binders.cc b/fuchsia/engine/browser/web_engine_browser_interface_binders.cc index 759ed388..61015560 100644 --- a/fuchsia/engine/browser/web_engine_browser_interface_binders.cc +++ b/fuchsia/engine/browser/web_engine_browser_interface_binders.cc
@@ -4,16 +4,12 @@ #include "fuchsia/engine/browser/web_engine_browser_interface_binders.h" -#include "fuchsia/engine/browser/cdm_provider_service.h" #include "fuchsia/engine/browser/frame_impl.h" #include "fuchsia/engine/browser/web_engine_media_resource_provider_impl.h" #include "mojo/public/cpp/bindings/pending_receiver.h" void PopulateFuchsiaFrameBinders( - mojo::BinderMapWithContext<content::RenderFrameHost*>* map, - CdmProviderService* cdm_provider_service) { + mojo::BinderMapWithContext<content::RenderFrameHost*>* map) { map->Add<mojom::WebEngineMediaResourceProvider>( base::BindRepeating(&WebEngineMediaResourceProviderImpl::Bind)); - map->Add<media::mojom::FuchsiaCdmProvider>(base::BindRepeating( - &CdmProviderService::Bind, base::Unretained(cdm_provider_service))); }
diff --git a/fuchsia/engine/browser/web_engine_browser_interface_binders.h b/fuchsia/engine/browser/web_engine_browser_interface_binders.h index 6f29c86..bc87f65 100644 --- a/fuchsia/engine/browser/web_engine_browser_interface_binders.h +++ b/fuchsia/engine/browser/web_engine_browser_interface_binders.h
@@ -11,14 +11,11 @@ class RenderFrameHost; } // namespace content -class CdmProviderService; - // PopulateFuchsiaFrameBinders() registers BrowserInterfaceBroker's // GetInterface() handler callbacks for Fuchsia-specific RenferFrame-scoped // interfaces. This mechanism will replace interface registries and binders used // for handling InterfaceProvider's GetInterface() calls (see crbug.com/718652). void PopulateFuchsiaFrameBinders( - mojo::BinderMapWithContext<content::RenderFrameHost*>* map, - CdmProviderService* cdm_provider_service); + mojo::BinderMapWithContext<content::RenderFrameHost*>* map); #endif // FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_BROWSER_INTERFACE_BINDERS_H_
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.cc b/fuchsia/engine/browser/web_engine_browser_main_parts.cc index 50dca05c..1c5b335 100644 --- a/fuchsia/engine/browser/web_engine_browser_main_parts.cc +++ b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
@@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" +#include "base/files/file_path.h" #include "base/files/important_file_writer_cleaner.h" #include "base/fuchsia/file_utils.h" #include "base/fuchsia/fuchsia_logging.h" @@ -40,7 +41,6 @@ #include "content/public/common/result_codes.h" #include "fuchsia/base/inspect.h" #include "fuchsia/base/legacymetrics_client.h" -#include "fuchsia/engine/browser/cdm_provider_service.h" #include "fuchsia/engine/browser/context_impl.h" #include "fuchsia/engine/browser/web_engine_browser_context.h" #include "fuchsia/engine/browser/web_engine_devtools_controller.h" @@ -48,9 +48,11 @@ #include "fuchsia/engine/common/cast_streaming.h" #include "fuchsia/engine/switches.h" #include "gpu/command_buffer/service/gpu_switches.h" +#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h" #include "net/http/http_util.h" #include "services/network/public/cpp/network_quality_tracker.h" #include "services/network/public/mojom/network_context.mojom.h" +#include "third_party/widevine/cdm/widevine_cdm_common.h" #include "ui/aura/screen_ozone.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/switches.h" @@ -78,6 +80,58 @@ kChildProcessHistogramFetchTimeout); } +template <typename KeySystemInterface> +fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> ConnectToKeySystem() { + static_assert( + (std::is_same<KeySystemInterface, fuchsia::media::drm::Widevine>::value || + std::is_same<KeySystemInterface, fuchsia::media::drm::PlayReady>::value), + "KeySystemInterface must be either fuchsia::media::drm::Widevine or " + "fuchsia::media::drm::PlayReady"); + + fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> key_system; + base::ComponentContextForProcess()->svc()->Connect(key_system.NewRequest(), + KeySystemInterface::Name_); + return key_system; +} + +std::unique_ptr<media::FuchsiaCdmManager> CreateCdmManager() { + media::FuchsiaCdmManager::CreateKeySystemCallbackMap + create_key_system_callbacks; + + const auto* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kEnableWidevine)) { + create_key_system_callbacks.emplace( + kWidevineKeySystem, + base::BindRepeating( + &ConnectToKeySystem<fuchsia::media::drm::Widevine>)); + } + + std::string playready_key_system = + command_line->GetSwitchValueASCII(switches::kPlayreadyKeySystem); + if (!playready_key_system.empty()) { + create_key_system_callbacks.emplace( + playready_key_system, + base::BindRepeating( + &ConnectToKeySystem<fuchsia::media::drm::PlayReady>)); + } + + std::string cdm_data_directory = + command_line->GetSwitchValueASCII(switches::kCdmDataDirectory); + + absl::optional<uint64_t> cdm_data_quota_bytes; + if (command_line->HasSwitch(switches::kCdmDataQuotaBytes)) { + uint64_t value = 0; + CHECK(base::StringToUint64( + command_line->GetSwitchValueASCII(switches::kCdmDataQuotaBytes), + &value)); + cdm_data_quota_bytes = value; + } + + return std::make_unique<media::FuchsiaCdmManager>( + std::move(create_key_system_callbacks), + base::FilePath(cdm_data_directory), cdm_data_quota_bytes); +} + // Implements the fuchsia.web.FrameHost protocol using a ContextImpl with // incognito browser context. class FrameHostImpl final : public fuchsia::web::FrameHost { @@ -226,10 +280,9 @@ screen_ = std::move(screen_ozone); display::Screen::SetScreenInstance(screen_.get()); - // Create the CdmProviderService at startup rather than on-demand, - // to allow it to perform potentially expensive startup work in the - // background. - cdm_provider_service_ = std::make_unique<CdmProviderService>(); + // Create the FuchsiaCdmManager at startup rather than on-demand, to allow it + // to perform potentially expensive startup work in the background. + cdm_manager_ = CreateCdmManager(); // Disable RenderFrameHost's Javascript injection restrictions so that the // Context and Frames can implement their own JS injection policy at a higher
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.h b/fuchsia/engine/browser/web_engine_browser_main_parts.h index a4b810e..b445a49 100644 --- a/fuchsia/engine/browser/web_engine_browser_main_parts.h +++ b/fuchsia/engine/browser/web_engine_browser_main_parts.h
@@ -34,11 +34,14 @@ class LegacyMetricsClient; } +namespace media { +class FuchsiaCdmManager; +} + namespace sys { class ComponentInspector; } -class CdmProviderService; class WebEngineMemoryInspector; class WEB_ENGINE_EXPORT WebEngineBrowserMainParts @@ -56,9 +59,6 @@ WebEngineDevToolsController* devtools_controller() const { return devtools_controller_.get(); } - CdmProviderService* cdm_provider_service() const { - return cdm_provider_service_.get(); - } // content::BrowserMainParts overrides. int PreEarlyInitialization() override; @@ -107,7 +107,7 @@ std::unique_ptr<WebEngineDevToolsController> devtools_controller_; std::unique_ptr<cr_fuchsia::LegacyMetricsClient> legacy_metrics_client_; - std::unique_ptr<CdmProviderService> cdm_provider_service_; + std::unique_ptr<media::FuchsiaCdmManager> cdm_manager_; // Used to respond to changes to the system's current locale. std::unique_ptr<base::FuchsiaIntlProfileWatcher> intl_profile_watcher_;
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.cc b/fuchsia/engine/browser/web_engine_content_browser_client.cc index 0469a491..fb20e14 100644 --- a/fuchsia/engine/browser/web_engine_content_browser_client.cc +++ b/fuchsia/engine/browser/web_engine_content_browser_client.cc
@@ -148,9 +148,7 @@ void WebEngineContentBrowserClient::RegisterBrowserInterfaceBindersForFrame( content::RenderFrameHost* render_frame_host, mojo::BinderMapWithContext<content::RenderFrameHost*>* map) { - CdmProviderService* const provider = main_parts_->cdm_provider_service(); - DCHECK(provider); - PopulateFuchsiaFrameBinders(map, provider); + PopulateFuchsiaFrameBinders(map); } void WebEngineContentBrowserClient::
diff --git a/fuchsia/engine/renderer/web_engine_audio_device_factory.cc b/fuchsia/engine/renderer/web_engine_audio_device_factory.cc index a0d9cea..0fb4ac9f 100644 --- a/fuchsia/engine/renderer/web_engine_audio_device_factory.cc +++ b/fuchsia/engine/renderer/web_engine_audio_device_factory.cc
@@ -78,7 +78,7 @@ auto* render_frame = GetRenderFrameForToken(frame_token); CHECK(render_frame); - // Connect FuchsiaMediaResourceProvider. + // Connect WebEngineMediaResourceProvider. mojo::Remote<mojom::WebEngineMediaResourceProvider> media_resource_provider; render_frame->GetBrowserInterfaceBroker()->GetInterface( media_resource_provider.BindNewPipeAndPassReceiver());
diff --git a/fuchsia/engine/renderer/web_engine_audio_renderer.cc b/fuchsia/engine/renderer/web_engine_audio_renderer.cc index 5c8e83f8..16ee1138 100644 --- a/fuchsia/engine/renderer/web_engine_audio_renderer.cc +++ b/fuchsia/engine/renderer/web_engine_audio_renderer.cc
@@ -134,6 +134,7 @@ DCHECK(!init_cb_); init_cb_ = std::move(init_cb); + cdm_context_ = cdm_context; demuxer_stream_ = stream; client_ = client; @@ -148,28 +149,39 @@ audio_consumer_.events().OnEndOfStream = [this]() { OnEndOfStream(); }; RequestAudioConsumerStatus(); + InitializeStream(); + + // Call `init_cb_`, unless it's been called by OnError(). + if (init_cb_) { + std::move(init_cb_).Run(media::PIPELINE_OK); + } +} + +void WebEngineAudioRenderer::InitializeStream() { // AAC streams require bitstream conversion. Without it the demuxer may // produce decoded stream without ADTS headers which are required for AAC // streams in AudioConsumer. // TODO(crbug.com/1120095): Reconsider this logic. - if (stream->audio_decoder_config().codec() == media::AudioCodec::kAAC) { - stream->EnableBitstreamConverter(); + if (demuxer_stream_->audio_decoder_config().codec() == + media::AudioCodec::kAAC) { + demuxer_stream_->EnableBitstreamConverter(); } - if (stream->audio_decoder_config().is_encrypted()) { - if (!cdm_context) { + if (demuxer_stream_->audio_decoder_config().is_encrypted()) { + if (!cdm_context_) { DLOG(ERROR) << "No cdm context for encrypted stream."; OnError(media::AUDIO_RENDERER_ERROR); return; } - media::FuchsiaCdmContext* fuchsia_cdm = cdm_context->GetFuchsiaCdmContext(); + media::FuchsiaCdmContext* fuchsia_cdm = + cdm_context_->GetFuchsiaCdmContext(); if (fuchsia_cdm) { sysmem_buffer_stream_ = fuchsia_cdm->CreateStreamDecryptor(false); } else { sysmem_buffer_stream_ = std::make_unique<media::DecryptingSysmemBufferStream>( - &sysmem_allocator_, cdm_context, media::Decryptor::kAudio); + &sysmem_allocator_, cdm_context_, media::Decryptor::kAudio); } } else { @@ -179,8 +191,6 @@ } sysmem_buffer_stream_->Initialize(this, kBufferSize, kNumBuffers); - - std::move(init_cb_).Run(media::PIPELINE_OK); } void WebEngineAudioRenderer::UpdateVolume() { @@ -595,9 +605,14 @@ OnError(media::PIPELINE_ERROR_READ); } else if (read_status == media::DemuxerStream::kConfigChanged) { stream_sink_.Unbind(); - sysmem_buffer_stream_->Reset(); - InitializeStreamSink(); + // Re-initialize the stream for the new config. + InitializeStream(); + + // Continue reading the stream. Decryptor won't finish output buffer + // initialization until it starts receiving data on the input. + ScheduleReadDemuxerStream(); + client_->OnAudioConfigChange(demuxer_stream_->audio_decoder_config()); } else { DCHECK_EQ(read_status, media::DemuxerStream::kAborted);
diff --git a/fuchsia/engine/renderer/web_engine_audio_renderer.h b/fuchsia/engine/renderer/web_engine_audio_renderer.h index b613acf..a0adbc3 100644 --- a/fuchsia/engine/renderer/web_engine_audio_renderer.h +++ b/fuchsia/engine/renderer/web_engine_audio_renderer.h
@@ -101,6 +101,8 @@ // |volume_|. void UpdateVolume(); + void InitializeStream(); + // Callback for input_buffer_collection_.AcquireBuffers(). void OnBuffersAcquired( std::vector<media::VmoBuffer> buffers, @@ -170,6 +172,7 @@ float volume_ = 1.0; + media::CdmContext* cdm_context_ = nullptr; media::DemuxerStream* demuxer_stream_ = nullptr; bool is_demuxer_read_pending_ = false; bool drop_next_demuxer_read_result_ = false;
diff --git a/fuchsia/engine/renderer/web_engine_audio_renderer_test.cc b/fuchsia/engine/renderer/web_engine_audio_renderer_test.cc index 3f1ad83f..5998865 100644 --- a/fuchsia/engine/renderer/web_engine_audio_renderer_test.cc +++ b/fuchsia/engine/renderer/web_engine_audio_renderer_test.cc
@@ -464,25 +464,24 @@ // media::FuchsiaCdmContext implementation. std::unique_ptr<media::SysmemBufferStream> CreateStreamDecryptor( bool secure_mode) override { + ++num_decryptors_; return std::make_unique<AsyncSysmemBufferStream>(); } + + size_t num_decryptors() { return num_decryptors_; } + + private: + size_t num_decryptors_ = 0; }; } // namespace -struct RendererTestConfig { - bool simulate_fuchsia_cdm; -}; - -class WebEngineAudioRendererTest - : public testing::Test, - public testing::WithParamInterface<RendererTestConfig> { +class WebEngineAudioRendererTestBase : public testing::Test { public: - WebEngineAudioRendererTest() = default; - ~WebEngineAudioRendererTest() override = default; + WebEngineAudioRendererTestBase() = default; + ~WebEngineAudioRendererTestBase() override = default; void CreateUninitializedRenderer(); - void CreateTestDemuxerStream(); void InitializeRenderer(); void CreateAndInitializeRenderer(); void ProduceDemuxerPacket(base::TimeDelta duration); @@ -498,17 +497,20 @@ fuchsia::media::AudioSampleFormat fuchsia_sample_format, size_t bytes_per_sample_output); - // Starts playback from |start_time| at the specified |playback_rate| and + // Starts playback from `start_time` at the specified `playback_rate` and // verifies that the clock works correctly. void StartPlaybackAndVerifyClock(base::TimeDelta start_time, float playback_rate); + // Returns initial config for the `demuxer_stream_`. + virtual media::AudioDecoderConfig GetStreamConfig() = 0; + protected: base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::IO, base::test::TaskEnvironment::TimeSource::MOCK_TIME}; - std::unique_ptr<media::CdmContext> cdm_context_; + TestFuchsiaCdmContext cdm_context_; std::unique_ptr<TestAudioConsumer> audio_consumer_; std::unique_ptr<TestStreamSink> stream_sink_; std::unique_ptr<TestDemuxerStream> demuxer_stream_; @@ -519,7 +521,7 @@ base::TimeDelta demuxer_stream_pos_; }; -void WebEngineAudioRendererTest::CreateUninitializedRenderer() { +void WebEngineAudioRendererTestBase::CreateUninitializedRenderer() { fidl::InterfaceHandle<fuchsia::media::AudioConsumer> audio_consumer_handle; audio_consumer_ = std::make_unique<TestAudioConsumer>(audio_consumer_handle.NewRequest()); @@ -528,28 +530,15 @@ time_source_ = audio_renderer_->GetTimeSource(); } -void WebEngineAudioRendererTest::CreateTestDemuxerStream() { - media::AudioDecoderConfig config( - media::AudioCodec::kPCM, media::kSampleFormatF32, - media::CHANNEL_LAYOUT_MONO, kDefaultSampleRate, {}, - media::EncryptionScheme::kUnencrypted); - - if (GetParam().simulate_fuchsia_cdm) { - config.SetIsEncrypted(true); - cdm_context_ = std::make_unique<TestFuchsiaCdmContext>(); +void WebEngineAudioRendererTestBase::InitializeRenderer() { + if (!demuxer_stream_) { + demuxer_stream_ = std::make_unique<TestDemuxerStream>(GetStreamConfig()); } - demuxer_stream_ = std::make_unique<TestDemuxerStream>(config); -} - -void WebEngineAudioRendererTest::InitializeRenderer() { - if (!demuxer_stream_) - CreateTestDemuxerStream(); - base::RunLoop run_loop; media::PipelineStatus pipeline_status; audio_renderer_->Initialize( - demuxer_stream_.get(), cdm_context_.get(), &client_, + demuxer_stream_.get(), &cdm_context_, &client_, base::BindLambdaForTesting( [&run_loop, &pipeline_status](media::PipelineStatus s) { pipeline_status = s; @@ -564,12 +553,12 @@ task_environment_.RunUntilIdle(); } -void WebEngineAudioRendererTest::CreateAndInitializeRenderer() { +void WebEngineAudioRendererTestBase::CreateAndInitializeRenderer() { CreateUninitializedRenderer(); InitializeRenderer(); } -void WebEngineAudioRendererTest::ProduceDemuxerPacket( +void WebEngineAudioRendererTestBase::ProduceDemuxerPacket( base::TimeDelta duration) { // Create a dummy packet that contains just 1 byte. const size_t kBufferSize = 1; @@ -581,14 +570,15 @@ demuxer_stream_->QueueReadResult(TestDemuxerStream::ReadResult(buffer)); } -void WebEngineAudioRendererTest::FillDemuxerStream(base::TimeDelta end_pos) { +void WebEngineAudioRendererTestBase::FillDemuxerStream( + base::TimeDelta end_pos) { EXPECT_LT(demuxer_stream_pos_, end_pos); while (demuxer_stream_pos_ < end_pos) { ProduceDemuxerPacket(kPacketDuration); } } -void WebEngineAudioRendererTest::FillBuffer() { +void WebEngineAudioRendererTestBase::FillBuffer() { if (!stream_sink_) { stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); } @@ -615,7 +605,7 @@ EXPECT_EQ(client_.buffering_state(), media::BUFFERING_HAVE_ENOUGH); } -void WebEngineAudioRendererTest::StartPlayback(base::TimeDelta start_time) { +void WebEngineAudioRendererTestBase::StartPlayback(base::TimeDelta start_time) { EXPECT_FALSE(audio_consumer_->started()); time_source_->SetMediaTime(start_time); @@ -629,7 +619,7 @@ task_environment_.RunUntilIdle(); } -void WebEngineAudioRendererTest::CheckGetWallClockTimes( +void WebEngineAudioRendererTestBase::CheckGetWallClockTimes( absl::optional<base::TimeDelta> media_timestamp, base::TimeTicks expected_wall_clock, bool is_time_moving) { @@ -642,7 +632,7 @@ EXPECT_EQ(result, is_time_moving); } -void WebEngineAudioRendererTest::StartPlaybackAndVerifyClock( +void WebEngineAudioRendererTestBase::StartPlaybackAndVerifyClock( base::TimeDelta start_time, float playback_rate) { time_source_->SetMediaTime(start_time); @@ -685,6 +675,78 @@ true); } +void WebEngineAudioRendererTestBase::TestPcmStream( + media::SampleFormat sample_format, + size_t bytes_per_sample_input, + fuchsia::media::AudioSampleFormat fuchsia_sample_format, + size_t bytes_per_sample_output) { + media::AudioDecoderConfig config( + media::AudioCodec::kPCM, sample_format, media::CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, {}, media::EncryptionScheme::kUnencrypted); + + demuxer_stream_ = std::make_unique<TestDemuxerStream>(config); + + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); + EXPECT_EQ(stream_sink_->stream_type().sample_format, fuchsia_sample_format); + + // Create a dummy packet that contains 1 sample. + const size_t kNumSamples = 10; + const size_t kChannels = 2; + size_t input_buffer_size = kNumSamples * kChannels * bytes_per_sample_input; + scoped_refptr<media::DecoderBuffer> buffer = + new media::DecoderBuffer(input_buffer_size); + buffer->set_timestamp(demuxer_stream_pos_); + buffer->set_duration(kPacketDuration); + for (size_t i = 0; i < input_buffer_size; ++i) { + buffer->writable_data()[i] = i; + } + demuxer_stream_->QueueReadResult(TestDemuxerStream::ReadResult(buffer)); + + // Start playback. The renderer will process the packet queued above. + audio_renderer_->StartPlaying(); + task_environment_.RunUntilIdle(); + + ASSERT_EQ(stream_sink_->received_packets()->size(), 1U); + auto packet = stream_sink_->received_packets()->at(0); + + // Read and verify packet content + size_t output_size = kNumSamples * kChannels * bytes_per_sample_output; + EXPECT_EQ(packet.payload_size, output_size); + uint8_t data[output_size]; + zx_status_t result = stream_sink_->buffers()[packet.payload_buffer_id].read( + data, 0, output_size); + ZX_CHECK(result == ZX_OK, result); + + for (size_t i = 0; i < output_size; ++i) { + size_t pos_within_sample = i % bytes_per_sample_output; + uint8_t expected_value = + (pos_within_sample < bytes_per_sample_input) + ? (i / bytes_per_sample_output * bytes_per_sample_input + + pos_within_sample) + : 0; + EXPECT_EQ(data[i], expected_value); + } +} + +struct RendererTestConfig { + bool simulate_fuchsia_cdm; +}; + +class WebEngineAudioRendererTest + : public WebEngineAudioRendererTestBase, + public testing::WithParamInterface<RendererTestConfig> { + public: + media::AudioDecoderConfig GetStreamConfig() final { + auto encryption_scheme = GetParam().simulate_fuchsia_cdm + ? media::EncryptionScheme::kCenc + : media::EncryptionScheme::kUnencrypted; + return media::AudioDecoderConfig( + media::AudioCodec::kPCM, media::kSampleFormatF32, + media::CHANNEL_LAYOUT_MONO, kDefaultSampleRate, {}, encryption_scheme); + } +}; + // Run all WebEngineAudioRendererTests with CDM enabled and disabled. INSTANTIATE_TEST_SUITE_P(Unencrypted, WebEngineAudioRendererTest, @@ -793,7 +855,53 @@ kSeekPos.ToZxDuration()); } -TEST_P(WebEngineAudioRendererTest, ChangeConfig) { +TEST_F(WebEngineAudioRendererTest, PcmU8Stream) { + TestPcmStream(media::kSampleFormatU8, 1, + fuchsia::media::AudioSampleFormat::UNSIGNED_8, 1); +} + +TEST_F(WebEngineAudioRendererTest, PcmS16Stream) { + TestPcmStream(media::kSampleFormatS16, 2, + fuchsia::media::AudioSampleFormat::SIGNED_16, 2); +} + +TEST_F(WebEngineAudioRendererTest, PcmS24Stream) { + TestPcmStream(media::kSampleFormatS24, 3, + fuchsia::media::AudioSampleFormat::SIGNED_24_IN_32, 4); +} + +TEST_F(WebEngineAudioRendererTest, PcmF32Stream) { + TestPcmStream(media::kSampleFormatF32, 4, + fuchsia::media::AudioSampleFormat::FLOAT, 4); +} + +struct ConfigChangeTestConfig { + bool encrypted_head; + bool encrypted_tail; +}; + +class WebEngineAudioRendererConfgChangeTest + : public WebEngineAudioRendererTestBase, + public testing::WithParamInterface<ConfigChangeTestConfig> { + media::AudioDecoderConfig GetStreamConfig() final { + auto encryption_scheme = GetParam().encrypted_head + ? media::EncryptionScheme::kCenc + : media::EncryptionScheme::kUnencrypted; + return media::AudioDecoderConfig( + media::AudioCodec::kPCM, media::kSampleFormatF32, + media::CHANNEL_LAYOUT_MONO, kDefaultSampleRate, {}, encryption_scheme); + } +}; + +// Run all WebEngineAudioRendererTests with CDM enabled and disabled. +INSTANTIATE_TEST_SUITE_P(ConfigChange, + WebEngineAudioRendererConfgChangeTest, + testing::Values(ConfigChangeTestConfig{false, false}, + ConfigChangeTestConfig{false, true}, + ConfigChangeTestConfig{true, false}, + ConfigChangeTestConfig{true, true})); + +TEST_P(WebEngineAudioRendererConfgChangeTest, ConfigChange) { ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); ASSERT_NO_FATAL_FAILURE(StartPlayback()); @@ -802,24 +910,41 @@ // Queue packets up to kConfigChangePos. FillDemuxerStream(kConfigChangePos); + // Verify that decryptor was initialized only if the beginning of the stream + // is encrypted. + EXPECT_EQ(cdm_context_.num_decryptors(), GetParam().encrypted_head ? 1U : 0U); + + // New Config const size_t kNewSampleRate = 44100; const std::vector<uint8_t> kArbitraryExtraData = {1, 2, 3}; + auto mew_encryption_scheme = GetParam().encrypted_tail + ? media::EncryptionScheme::kCenc + : media::EncryptionScheme::kUnencrypted; media::AudioDecoderConfig updated_config( media::AudioCodec::kOpus, media::kSampleFormatF32, media::CHANNEL_LAYOUT_STEREO, kNewSampleRate, kArbitraryExtraData, - media::EncryptionScheme::kUnencrypted); + mew_encryption_scheme); + demuxer_stream_->QueueReadResult( TestDemuxerStream::ReadResult(updated_config)); // Queue one more packet with the new config. - ProduceDemuxerPacket(kPacketDuration); + ProduceDemuxerPacket(kPacketDuration * 2); task_environment_.FastForwardBy(kConfigChangePos); // The renderer should have created new StreamSink when config was changed. - auto new_stream_sink = audio_consumer_->TakeStreamSink(); + auto new_stream_sink = audio_consumer_->WaitStreamSinkConnected(); ASSERT_TRUE(new_stream_sink); + task_environment_.RunUntilIdle(); + + // Verify that decryptor was re-created if the stream is encrypted after + // the config change. + EXPECT_EQ(cdm_context_.num_decryptors(), + (GetParam().encrypted_head ? 1U : 0U) + + (GetParam().encrypted_tail ? 1U : 0U)); + ASSERT_TRUE(client_.last_config_change().has_value()); EXPECT_TRUE(client_.last_config_change()->Matches(updated_config)); @@ -999,7 +1124,7 @@ // StartPlaying() is handled correctly. AudioConsumer::Start() should be sent // only after CreateStreamSink(). See crbug.com/1219147 . TEST_P(WebEngineAudioRendererTest, PlaybackBeforeSinkCreation) { - CreateTestDemuxerStream(); + demuxer_stream_ = std::make_unique<TestDemuxerStream>(GetStreamConfig()); const auto kStreamLength = base::Milliseconds(100); FillDemuxerStream(kStreamLength); demuxer_stream_->QueueReadResult( @@ -1019,77 +1144,3 @@ stream_sink_ = audio_consumer_->TakeStreamSink(); EXPECT_GT(stream_sink_->received_packets()->size(), 0U); } - -void WebEngineAudioRendererTest::TestPcmStream( - media::SampleFormat sample_format, - size_t bytes_per_sample_input, - fuchsia::media::AudioSampleFormat fuchsia_sample_format, - size_t bytes_per_sample_output) { - media::AudioDecoderConfig config( - media::AudioCodec::kPCM, sample_format, media::CHANNEL_LAYOUT_STEREO, - kDefaultSampleRate, {}, media::EncryptionScheme::kUnencrypted); - - demuxer_stream_ = std::make_unique<TestDemuxerStream>(config); - - ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); - stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); - EXPECT_EQ(stream_sink_->stream_type().sample_format, fuchsia_sample_format); - - // Create a dummy packet that contains 1 sample. - const size_t kNumSamples = 10; - const size_t kChannels = 2; - size_t input_buffer_size = kNumSamples * kChannels * bytes_per_sample_input; - scoped_refptr<media::DecoderBuffer> buffer = - new media::DecoderBuffer(input_buffer_size); - buffer->set_timestamp(demuxer_stream_pos_); - buffer->set_duration(kPacketDuration); - for (size_t i = 0; i < input_buffer_size; ++i) { - buffer->writable_data()[i] = i; - } - demuxer_stream_->QueueReadResult(TestDemuxerStream::ReadResult(buffer)); - - // Start playback. The renderer will process the packet queued above. - audio_renderer_->StartPlaying(); - task_environment_.RunUntilIdle(); - - ASSERT_EQ(stream_sink_->received_packets()->size(), 1U); - auto packet = stream_sink_->received_packets()->at(0); - - // Read and verify packet content - size_t output_size = kNumSamples * kChannels * bytes_per_sample_output; - EXPECT_EQ(packet.payload_size, output_size); - uint8_t data[output_size]; - zx_status_t result = stream_sink_->buffers()[packet.payload_buffer_id].read( - data, 0, output_size); - ZX_CHECK(result == ZX_OK, result); - - for (size_t i = 0; i < output_size; ++i) { - size_t pos_within_sample = i % bytes_per_sample_output; - uint8_t expected_value = - (pos_within_sample < bytes_per_sample_input) - ? (i / bytes_per_sample_output * bytes_per_sample_input + - pos_within_sample) - : 0; - EXPECT_EQ(data[i], expected_value); - } -} - -TEST_F(WebEngineAudioRendererTest, PcmU8Stream) { - TestPcmStream(media::kSampleFormatU8, 1, - fuchsia::media::AudioSampleFormat::UNSIGNED_8, 1); -} - -TEST_F(WebEngineAudioRendererTest, PcmS16Stream) { - TestPcmStream(media::kSampleFormatS16, 2, - fuchsia::media::AudioSampleFormat::SIGNED_16, 2); -} - -TEST_F(WebEngineAudioRendererTest, PcmS24Stream) { - TestPcmStream(media::kSampleFormatS24, 3, - fuchsia::media::AudioSampleFormat::SIGNED_24_IN_32, 4); -} - -TEST_F(WebEngineAudioRendererTest, PcmF32Stream) { - TestPcmStream(media::kSampleFormatF32, 4, - fuchsia::media::AudioSampleFormat::FLOAT, 4); -}
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd index e70f67a..f3d770d6 100644 --- a/ios/chrome/app/strings/ios_chromium_strings.grd +++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -22,6 +22,7 @@ <output filename="ios_chromium_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_chromium_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_chromium_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_chromium_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_chromium_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_chromium_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_chromium_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd index 79d18844..b29e8613 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings.grd +++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -22,6 +22,7 @@ <output filename="ios_google_chrome_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_google_chrome_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_google_chrome_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_google_chrome_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_google_chrome_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_google_chrome_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_google_chrome_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 37906b6..4d0720b 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -3035,7 +3035,7 @@ Learn More </message> <message name="IDS_IOS_TOOLS_MENU_FOLLOW" desc="The iOS menu item for following web content. [iOS only]"> - Follow + Follow <ph name="DOMAIN_NAME">$1<ex>google.com</ex></ph> </message> <message name="IDS_IOS_TOOLS_MENU_UNFOLLOW" desc="The iOS menu item for unfollowing web content. [iOS only]"> Unfollow
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_FOLLOW.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_FOLLOW.png.sha1 index be0a067..cc03201e 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_FOLLOW.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_FOLLOW.png.sha1
@@ -1 +1 @@ -8f864cc2cb1c57c73cc8d199dd6a0cb029089659 \ No newline at end of file +273e7e082df194f812c6e5984f1c5a018a263656 \ No newline at end of file
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state.h b/ios/chrome/browser/browser_state/chrome_browser_state.h index 0c02b58..46b2944 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state.h +++ b/ios/chrome/browser/browser_state/chrome_browser_state.h
@@ -35,6 +35,10 @@ class WebUIIOS; } +namespace policy { +class UserCloudPolicyManager; +} + enum class ChromeBrowserStateType { REGULAR_BROWSER_STATE, INCOGNITO_BROWSER_STATE, @@ -82,6 +86,10 @@ // for this BrowserState. May return nullptr if policy is disabled. virtual BrowserStatePolicyConnector* GetPolicyConnector() = 0; + // Returns a pointer to the UserCloudPolicyManager that is a facade for the + // user cloud policy system. + virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() = 0; + // Retrieves a pointer to the PrefService that manages the preferences. virtual PrefService* GetPrefs() = 0;
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h index b025644..9c12d64e 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h +++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
@@ -12,6 +12,7 @@ namespace policy { class SchemaRegistry; +class UserCloudPolicyManager; } namespace sync_preferences { @@ -40,6 +41,7 @@ void DestroyOffTheRecordChromeBrowserState() override; PrefProxyConfigTracker* GetProxyConfigTracker() override; BrowserStatePolicyConnector* GetPolicyConnector() override; + policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override; PrefService* GetPrefs() override; ChromeBrowserStateIOData* GetIOData() override; void ClearNetworkingHistorySince(base::Time time, @@ -78,8 +80,10 @@ // happens in reverse order of declaration. // |policy_connector_| and its associated |policy_schema_registry_| must - // outlive |prefs_|. + // outlive |prefs_|. |policy_connector_| depends on the policy provider + // |user_cloud_policy_manager_| which depends on |policy_schema_registry_|. std::unique_ptr<policy::SchemaRegistry> policy_schema_registry_; + std::unique_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_; std::unique_ptr<BrowserStatePolicyConnector> policy_connector_; // Keep |prefs_| above the rest for destruction order because |io_data_| and
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm index 31beece..28a0efd 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm
@@ -14,6 +14,8 @@ #include "base/threading/thread_restrictions.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" +#include "components/policy/core/common/configuration_policy_provider.h" #include "components/policy/core/common/schema_registry.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/json_pref_store.h" @@ -108,8 +110,18 @@ DCHECK(connector); policy_schema_registry_ = BuildSchemaRegistryForBrowserState( this, connector->GetChromeSchema(), connector->GetSchemaRegistry()); + + // Create the UserCloudPolicyManager and force it to load immediately since + // BrowserState is loaded synchronously. + user_cloud_policy_manager_ = policy::UserCloudPolicyManager::Create( + GetStatePath(), policy_schema_registry_.get(), + /*force_immediate_load=*/true, GetIOTaskRunner(), + base::BindRepeating(&ApplicationContext::GetNetworkConnectionTracker, + base::Unretained(GetApplicationContext()))); + policy_connector_ = BuildBrowserStatePolicyConnector( - policy_schema_registry_.get(), connector); + policy_schema_registry_.get(), connector, + user_cloud_policy_manager_.get()); } RegisterBrowserStatePrefs(pref_registry_.get()); @@ -148,8 +160,21 @@ ChromeBrowserStateImpl::~ChromeBrowserStateImpl() { BrowserStateDependencyManager::GetInstance()->DestroyBrowserStateServices( this); + // Warning: the order for shutting down the BrowserState objects is important + // because of interdependencies. Ideally the order for shutting down the + // objects should be backward of their declaration in class attributes. + if (pref_proxy_config_tracker_) pref_proxy_config_tracker_->DetachFromPrefService(); + + // Here, (1) the browser state services may + // depend on `policy_connector_` and `user_cloud_policy_manager_`, and (2) + // `policy_connector_` depends on `user_cloud_policy_manager_`. The + // dependencies have to be shut down backward. + policy_connector_->Shutdown(); + if (user_cloud_policy_manager_) + user_cloud_policy_manager_->Shutdown(); + DestroyOffTheRecordChromeBrowserState(); } @@ -185,6 +210,11 @@ return nullptr; } +policy::UserCloudPolicyManager* +ChromeBrowserStateImpl::GetUserCloudPolicyManager() { + return user_cloud_policy_manager_.get(); +} + PrefService* ChromeBrowserStateImpl::GetPrefs() { DCHECK(prefs_); // Should explicitly be initialized. return prefs_.get();
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h index a83da76..b86d547 100644 --- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h +++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
@@ -13,6 +13,10 @@ class PrefServiceSyncable; } +namespace policy { +class UserCloudPolicyManager; +} + // The implementation of ChromeBrowserState that is used for incognito browsing. // Each OffTheRecordChromeBrowserStateImpl instance is associated with and owned // by a non-incognito ChromeBrowserState instance. @@ -32,6 +36,7 @@ void DestroyOffTheRecordChromeBrowserState() override; PrefProxyConfigTracker* GetProxyConfigTracker() override; BrowserStatePolicyConnector* GetPolicyConnector() override; + policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override; PrefService* GetPrefs() override; ChromeBrowserStateIOData* GetIOData() override; void ClearNetworkingHistorySince(base::Time time,
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm index e6af9bc..3bef75d 100644 --- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm +++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm
@@ -86,6 +86,12 @@ return GetOriginalChromeBrowserState()->GetPolicyConnector(); } +policy::UserCloudPolicyManager* +OffTheRecordChromeBrowserStateImpl::GetUserCloudPolicyManager() { + // Forward the call to the original (non-OTR) browser state. + return GetOriginalChromeBrowserState()->GetUserCloudPolicyManager(); +} + PrefService* OffTheRecordChromeBrowserStateImpl::GetPrefs() { return prefs_.get(); }
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.h b/ios/chrome/browser/browser_state/test_chrome_browser_state.h index 533dbc9..53698af 100644 --- a/ios/chrome/browser/browser_state/test_chrome_browser_state.h +++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.h
@@ -23,6 +23,10 @@ class TestingPrefServiceSyncable; } +namespace policy { +class UserCloudPolicyManager; +} + // This class is the implementation of ChromeBrowserState used for testing. class TestChromeBrowserState final : public ChromeBrowserState { public: @@ -60,6 +64,7 @@ ProtocolHandlerMap* protocol_handlers) override; scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory() override; + policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override; // This method is defined as empty following the paradigm of // TestingProfile::DestroyOffTheRecordProfile(). @@ -123,6 +128,11 @@ void SetPolicyConnector( std::unique_ptr<BrowserStatePolicyConnector> policy_connector); + // Sets a UserCloudPolicyManager for test. + void SetUserCloudPolicyManager( + std::unique_ptr<policy::UserCloudPolicyManager> + user_cloud_policy_manager); + // Creates the TestChromeBrowserState using previously-set settings. std::unique_ptr<TestChromeBrowserState> Build(); @@ -134,6 +144,7 @@ base::FilePath state_path_; std::unique_ptr<sync_preferences::PrefServiceSyncable> pref_service_; + std::unique_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_; std::unique_ptr<BrowserStatePolicyConnector> policy_connector_; TestingFactories testing_factories_; @@ -147,7 +158,9 @@ std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs, TestingFactories testing_factories, RefcountedTestingFactories refcounted_testing_factories, - std::unique_ptr<BrowserStatePolicyConnector> policy_connector); + std::unique_ptr<BrowserStatePolicyConnector> policy_connector, + std::unique_ptr<policy::UserCloudPolicyManager> + user_cloud_policy_manager); private: friend class Builder; @@ -169,6 +182,7 @@ std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs_; sync_preferences::TestingPrefServiceSyncable* testing_prefs_; + std::unique_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_; std::unique_ptr<BrowserStatePolicyConnector> policy_connector_; // A SharedURLLoaderFactory for test.
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm index 2b7309ce..76235763 100644 --- a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm +++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
@@ -20,6 +20,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "components/keyed_service/core/service_access_type.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" #include "components/profile_metrics/browser_profile_type.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/sync_preferences/testing_pref_service_syncable.h" @@ -74,12 +75,14 @@ std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs, TestingFactories testing_factories, RefcountedTestingFactories refcounted_testing_factories, - std::unique_ptr<BrowserStatePolicyConnector> policy_connector) + std::unique_ptr<BrowserStatePolicyConnector> policy_connector, + std::unique_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager) : ChromeBrowserState(base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), state_path_(path), prefs_(std::move(prefs)), testing_prefs_(nullptr), + user_cloud_policy_manager_(std::move(user_cloud_policy_manager)), policy_connector_(std::move(policy_connector)), otr_browser_state_(nullptr), original_browser_state_(nullptr) { @@ -105,6 +108,14 @@ // tear it down first. otr_browser_state_.reset(); + // Here, (1) the browser state services may + // depend on `policy_connector_` and `user_cloud_policy_manager_`, and (2) + // `policy_connector_` depends on `user_cloud_policy_manager_`. The + // dependencies have to be shut down backward. + policy_connector_->Shutdown(); + if (user_cloud_policy_manager_) + user_cloud_policy_manager_->Shutdown(); + BrowserStateDependencyManager::GetInstance()->DestroyBrowserStateServices( this); } @@ -295,13 +306,24 @@ policy_connector_ = std::move(policy_connector); } +void TestChromeBrowserState::Builder::SetUserCloudPolicyManager( + std::unique_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager) { + user_cloud_policy_manager_ = std::move(user_cloud_policy_manager); +} + +policy::UserCloudPolicyManager* +TestChromeBrowserState::GetUserCloudPolicyManager() { + return user_cloud_policy_manager_.get(); +} + std::unique_ptr<TestChromeBrowserState> TestChromeBrowserState::Builder::Build() { DCHECK(!build_called_); build_called_ = true; return base::WrapUnique(new TestChromeBrowserState( state_path_, std::move(pref_service_), std::move(testing_factories_), - std::move(refcounted_testing_factories_), std::move(policy_connector_))); + std::move(refcounted_testing_factories_), std::move(policy_connector_), + std::move(user_cloud_policy_manager_))); } scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn index cc61db0..521cd67 100644 --- a/ios/chrome/browser/flags/BUILD.gn +++ b/ios/chrome/browser/flags/BUILD.gn
@@ -66,7 +66,6 @@ "//ios/chrome/browser/ui/ntp:feature_flags", "//ios/chrome/browser/ui/overlays/infobar_banner:feature_flags", "//ios/chrome/browser/ui/popup_menu/overflow_menu:feature_flags", - "//ios/chrome/browser/ui/reading_list:features", "//ios/chrome/browser/ui/start_surface:feature_flags", "//ios/chrome/browser/ui/tab_switcher/tab_grid:features", "//ios/chrome/browser/ui/toolbar_container:feature_flags",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index b0028aa..3978beeb 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -77,7 +77,6 @@ #import "ios/chrome/browser/ui/ntp/new_tab_page_feature.h" #import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_features.h" #import "ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #import "ios/chrome/browser/ui/start_surface/start_surface_features.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/features.h" #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h" @@ -626,9 +625,6 @@ {"incognito-ntp-revamp", flag_descriptions::kIncognitoNtpRevampName, flag_descriptions::kIncognitoNtpRevampDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kIncognitoNtpRevamp)}, - {"reading-list-messages", flag_descriptions::kReadingListMessagesName, - flag_descriptions::kReadingListMessagesDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kReadingListMessages)}, {"sync-trusted-vault-passphrase-ios-rpc", flag_descriptions::kSyncTrustedVaultPassphraseiOSRPCName, flag_descriptions::kSyncTrustedVaultPassphraseiOSRPCDescription, @@ -741,9 +737,6 @@ flag_descriptions::kLazilyCreateWebStateOnRestorationDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(web::features::kEnableUnrealizedWebStates)}, - {"reading-list-time-to-read", flag_descriptions::kReadingListTimeToReadName, - flag_descriptions::kReadingListTimeToReadDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kReadingListTimeToRead)}, {"enable-shortened-password-auto-fill-instruction", flag_descriptions::kEnableShortenedPasswordAutoFillInstructionName, flag_descriptions::kEnableShortenedPasswordAutoFillInstructionDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 5d4b831..cf30529 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -398,16 +398,6 @@ "Displays warning when user types or pastes a saved password into a " "phishing website."; -const char kReadingListMessagesName[] = "Enables Reading List Messages"; -const char kReadingListMessagesDescription[] = - "When enabled, a Messages prompt may be presented to allow the user to " - "save the current page to Reading List"; - -const char kReadingListTimeToReadName[] = "Enables Reading List Time To Read"; -const char kReadingListTimeToReadDescription[] = - "When enabled, a Time to Read estimate is added to each Reading List " - "entry."; - const char kRecordSnapshotSizeName[] = "Record the size of image and PDF snapshots in UMA histograms"; const char kRecordSnapshotSizeDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 90d9bd0..3cb6524 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -367,14 +367,6 @@ extern const char kPasswordReuseDetectionName[]; extern const char kPasswordReuseDetectionDescription[]; -// Title and description for the flag to enable the Reading List Messages. -extern const char kReadingListMessagesName[]; -extern const char kReadingListMessagesDescription[]; - -// Title and description for the flag to enable Reading List Time to Read. -extern const char kReadingListTimeToReadName[]; -extern const char kReadingListTimeToReadDescription[]; - // Title and description for the flag to native restore web states. extern const char kRestoreSessionFromCacheName[]; extern const char kRestoreSessionFromCacheDescription[];
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn index 2aabf7c..6829a14 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn +++ b/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn
@@ -34,7 +34,6 @@ "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/permissions", - "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate", "//ios/chrome/browser/main:public",
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm index 44d6174..3b8a45c 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
@@ -11,7 +11,6 @@ #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/update_password_infobar_interaction_handler.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/permissions/permissions_infobar_interaction_handler.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_interaction_handler.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.h" @@ -36,7 +35,5 @@ browser_agent->AddInfobarInteractionHandler( std::make_unique<SaveAddressProfileInfobarInteractionHandler>()); browser_agent->AddInfobarInteractionHandler( - std::make_unique<AddToReadingListInfobarInteractionHandler>(browser)); - browser_agent->AddInfobarInteractionHandler( std::make_unique<PermissionsInfobarInteractionHandler>()); }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/BUILD.gn deleted file mode 100644 index fbf373d..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/BUILD.gn +++ /dev/null
@@ -1,73 +0,0 @@ -# Copyright 2021 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. - -source_set("reading_list") { - configs += [ "//build/config/compiler:enable_arc" ] - sources = [ - "add_to_reading_list_infobar_banner_interaction_handler.h", - "add_to_reading_list_infobar_banner_interaction_handler.mm", - "add_to_reading_list_infobar_interaction_handler.h", - "add_to_reading_list_infobar_interaction_handler.mm", - "add_to_reading_list_infobar_modal_overlay_request_callback_installer.h", - "add_to_reading_list_infobar_modal_overlay_request_callback_installer.mm", - "add_to_reading_list_modal_infobar_interaction_handler.h", - "add_to_reading_list_modal_infobar_interaction_handler.mm", - ] - deps = [ - "//base", - "//components/autofill/core/browser", - "//ios/chrome/browser/infobars", - "//ios/chrome/browser/infobars:public", - "//ios/chrome/browser/infobars/overlays", - "//ios/chrome/browser/infobars/overlays:util", - "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers", - "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common", - "//ios/chrome/browser/main:public", - "//ios/chrome/browser/overlays", - "//ios/chrome/browser/overlays/public/infobar_banner", - "//ios/chrome/browser/overlays/public/infobar_modal", - "//ios/chrome/browser/reading_list", - "//ios/chrome/browser/ui/commands", - "//ios/chrome/browser/ui/reading_list:infobar", - "//ios/chrome/browser/web_state_list", - ] -} - -source_set("unit_tests") { - configs += [ "//build/config/compiler:enable_arc" ] - testonly = true - sources = [ - "add_to_reading_list_banner_infobar_interaction_handler_unittest.mm", - "add_to_reading_list_infobar_modal_overlay_request_callback_installer_unittest.mm", - "add_to_reading_list_modal_infobar_interaction_handler_unittest.mm", - ] - deps = [ - ":reading_list", - "//base/test:test_support", - "//ios/chrome/browser/browser_state:test_support", - "//ios/chrome/browser/infobars", - "//ios/chrome/browser/infobars:public", - "//ios/chrome/browser/infobars/overlays", - "//ios/chrome/browser/infobars/overlays:util", - "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test", - "//ios/chrome/browser/infobars/test", - "//ios/chrome/browser/main:test_support", - "//ios/chrome/browser/overlays", - "//ios/chrome/browser/overlays/public/common/infobars", - "//ios/chrome/browser/overlays/public/infobar_banner", - "//ios/chrome/browser/overlays/public/infobar_modal", - "//ios/chrome/browser/overlays/test", - "//ios/chrome/browser/reading_list:fakes", - "//ios/chrome/browser/ui/commands", - "//ios/chrome/browser/ui/infobars/test", - "//ios/chrome/browser/ui/reading_list:infobar", - "//ios/chrome/browser/web_state_list", - "//ios/chrome/browser/web_state_list:test_support", - "//ios/chrome/test:test_support", - "//ios/web/public/test", - "//ios/web/public/test/fakes", - "//testing/gtest", - "//third_party/ocmock", - ] -}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/DEPS b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/DEPS deleted file mode 100644 index ea07b0b..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/DEPS +++ /dev/null
@@ -1,15 +0,0 @@ -specific_include_rules = { - # TODO(crbug.com/1294160): Remove these dependencies. - "^add_to_reading_list_infobar_banner_interaction_handler.mm": [ - "+ios/chrome/browser/ui/commands/browser_commands.h", - "+ios/chrome/browser/ui/commands/command_dispatcher.h", - "+ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.h", - ], - "^add_to_reading_list_modal_infobar_interaction_handler.mm": [ - "+ios/chrome/browser/ui/commands/browser_commands.h", - "+ios/chrome/browser/ui/commands/command_dispatcher.h", - "+ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.h", - ], - -} -
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_banner_infobar_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_banner_infobar_interaction_handler_unittest.mm deleted file mode 100644 index 0e60e55..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_banner_infobar_interaction_handler_unittest.mm +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.h" - -#include "base/test/task_environment.h" -#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/infobars/infobar_manager_impl.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h" -#import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h" -#include "ios/chrome/browser/infobars/overlays/infobar_overlay_util.h" -#import "ios/chrome/browser/infobars/test/fake_infobar_ios.h" -#import "ios/chrome/browser/main/test_browser.h" -#import "ios/chrome/browser/overlays/public/overlay_request_queue.h" -#import "ios/chrome/browser/reading_list/fake_reading_list_model.h" -#import "ios/chrome/browser/ui/commands/browser_commands.h" -#import "ios/chrome/browser/ui/commands/command_dispatcher.h" -#import "ios/web/public/test/fakes/fake_navigation_manager.h" -#import "ios/web/public/test/fakes/fake_web_state.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#include "third_party/ocmock/gtest_support.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// Test fixture for ReadingListInfobarBannerInteractionHandler. -class ReadingListInfobarBannerInteractionHandlerTest : public PlatformTest { - public: - ReadingListInfobarBannerInteractionHandlerTest() { - browser_state_ = TestChromeBrowserState::Builder().Build(); - test_browser_ = std::make_unique<TestBrowser>(browser_state_.get()); - mock_command_receiver_ = OCMStrictProtocolMock(@protocol(BrowserCommands)); - handler_ = - std::make_unique<AddToReadingListInfobarBannerInteractionHandler>( - test_browser_.get()); - web_state_.SetNavigationManager( - std::make_unique<web::FakeNavigationManager>()); - InfobarOverlayRequestInserter::CreateForWebState(&web_state_); - InfoBarManagerImpl::CreateForWebState(&web_state_); - fake_reading_list_model_ = std::make_unique<FakeReadingListModel>(); - - [test_browser_->GetCommandDispatcher() - startDispatchingToTarget:mock_command_receiver_ - forProtocol:@protocol(BrowserCommands)]; - - std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>( - InfobarType::kInfobarTypeAddToReadingList, - std::make_unique<MockIOSAddToReadingListInfobarDelegate>( - fake_reading_list_model_.get(), &web_state_)); - infobar_ = infobar.get(); - InfoBarManagerImpl::FromWebState(&web_state_) - ->AddInfoBar(std::move(infobar)); - } - - void TearDown() override { - [test_browser_->GetCommandDispatcher() - stopDispatchingToTarget:mock_command_receiver_]; - EXPECT_OCMOCK_VERIFY(mock_command_receiver_); - PlatformTest::TearDown(); - } - - MockIOSAddToReadingListInfobarDelegate& mock_delegate() { - return *static_cast<MockIOSAddToReadingListInfobarDelegate*>( - infobar_->delegate()); - } - - protected: - base::test::TaskEnvironment task_environment_; - std::unique_ptr<TestChromeBrowserState> browser_state_; - std::unique_ptr<TestBrowser> test_browser_; - id mock_command_receiver_ = nil; - std::unique_ptr<AddToReadingListInfobarBannerInteractionHandler> handler_; - web::FakeWebState web_state_; - std::unique_ptr<FakeReadingListModel> fake_reading_list_model_; - InfoBarIOS* infobar_; -}; - -// Tests MainButtonTapped() calls Accept() on the mock delegate and resets -// the infobar to be accepted. -TEST_F(ReadingListInfobarBannerInteractionHandlerTest, MainButton) { - ASSERT_FALSE(infobar_->accepted()); - OCMExpect([mock_command_receiver_ showReadingListIPH]); - EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true)); - handler_->MainButtonTapped(infobar_); - EXPECT_TRUE(infobar_->accepted()); -}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.h deleted file mode 100644 index 5fdc692..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2021 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_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_BANNER_INTERACTION_HANDLER_H_ -#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_BANNER_INTERACTION_HANDLER_H_ - -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h" - -class Browser; -class IOSAddToReadingListInfobarDelegate; - -// Helper object that updates the model layer for interaction events with the -// add to reading list infobar banner UI. -class AddToReadingListInfobarBannerInteractionHandler - : public InfobarBannerInteractionHandler { - public: - AddToReadingListInfobarBannerInteractionHandler(Browser* browser); - ~AddToReadingListInfobarBannerInteractionHandler() override; - - // InfobarBannerInteractionHandler: - void MainButtonTapped(InfoBarIOS* infobar) override; - void BannerVisibilityChanged(InfoBarIOS* infobar, bool visible) override {} - - private: - IOSAddToReadingListInfobarDelegate* GetInfobarDelegate(InfoBarIOS* infobar); - - Browser* browser_; -}; - -#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_BANNER_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.mm deleted file mode 100644 index 87bf630..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.mm +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.h" - -#include "base/check.h" -#include "ios/chrome/browser/infobars/infobar_ios.h" -#import "ios/chrome/browser/main/browser.h" -#import "ios/chrome/browser/overlays/public/infobar_banner/add_to_reading_list_infobar_banner_overlay_request_config.h" -#import "ios/chrome/browser/overlays/public/infobar_banner/save_card_infobar_banner_overlay_request_config.h" -#import "ios/chrome/browser/ui/commands/browser_commands.h" -#import "ios/chrome/browser/ui/commands/command_dispatcher.h" -#import "ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -using reading_list_infobar_overlay::ReadingListBannerRequestConfig; - -#pragma mark - InfobarBannerInteractionHandler - -AddToReadingListInfobarBannerInteractionHandler:: - AddToReadingListInfobarBannerInteractionHandler(Browser* browser) - : InfobarBannerInteractionHandler( - ReadingListBannerRequestConfig::RequestSupport()), - browser_(browser) {} - -AddToReadingListInfobarBannerInteractionHandler:: - ~AddToReadingListInfobarBannerInteractionHandler() = default; - -void AddToReadingListInfobarBannerInteractionHandler::MainButtonTapped( - InfoBarIOS* infobar) { - IOSAddToReadingListInfobarDelegate* delegate = GetInfobarDelegate(infobar); - infobar->set_accepted(delegate->Accept()); - [static_cast<id<BrowserCommands>>(browser_->GetCommandDispatcher()) - showReadingListIPH]; -} - -#pragma mark - Private - -IOSAddToReadingListInfobarDelegate* -AddToReadingListInfobarBannerInteractionHandler::GetInfobarDelegate( - InfoBarIOS* infobar) { - IOSAddToReadingListInfobarDelegate* delegate = - IOSAddToReadingListInfobarDelegate::FromInfobarDelegate( - infobar->delegate()); - DCHECK(delegate); - return delegate; -}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.h deleted file mode 100644 index 4f60bda..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2021 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_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_INTERACTION_HANDLER_H_ -#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_INTERACTION_HANDLER_H_ - -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h" - -class Browser; - -// An InfobarInteractionHandler that updates the model layer for interaction -// events with the UI for add to reading list infobars. -class AddToReadingListInfobarInteractionHandler - : public InfobarInteractionHandler { - public: - AddToReadingListInfobarInteractionHandler(Browser* browser); - ~AddToReadingListInfobarInteractionHandler() override; -}; - -#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.mm deleted file mode 100644 index 255b53ce..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.mm +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_interaction_handler.h" - -#import "ios/chrome/browser/infobars/infobar_type.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_banner_interaction_handler.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -AddToReadingListInfobarInteractionHandler:: - AddToReadingListInfobarInteractionHandler(Browser* browser) - : InfobarInteractionHandler( - InfobarType::kInfobarTypeAddToReadingList, - std::make_unique<AddToReadingListInfobarBannerInteractionHandler>( - browser), - std::make_unique<ReadingListInfobarModalInteractionHandler>( - browser)) {} - -AddToReadingListInfobarInteractionHandler:: - ~AddToReadingListInfobarInteractionHandler() = default;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.h deleted file mode 100644 index a635add..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2021 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_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_MODAL_OVERLAY_REQUEST_CALLBACK_INSTALLER_H_ -#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_MODAL_OVERLAY_REQUEST_CALLBACK_INSTALLER_H_ - -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_overlay_request_callback_installer.h" - -#include "base/memory/weak_ptr.h" - -class ReadingListInfobarModalInteractionHandler; - -namespace reading_list_infobar_overlay { - -// Callback installer, intended to be subclassed, for infobar modal interaction -// events. -class ModalRequestCallbackInstaller - : public InfobarModalOverlayRequestCallbackInstaller { - public: - // Constructor for an instance that installs callbacks that forward - // interaction events to |interaction_handler|. - explicit ModalRequestCallbackInstaller( - ReadingListInfobarModalInteractionHandler* interaction_handler); - ~ModalRequestCallbackInstaller() override; - - private: - // Used as a callback for OverlayResponses dispatched through |request|'s - // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a - // reading_list_infobar_modal_responses::NeverAsk. - void NeverAskCallback(OverlayRequest* request, OverlayResponse* response); - - // OverlayRequestCallbackInstaller: - void InstallCallbacksInternal(OverlayRequest* request) override; - - // The handler for received responses. - ReadingListInfobarModalInteractionHandler* interaction_handler_ = nullptr; - - base::WeakPtrFactory<ModalRequestCallbackInstaller> weak_factory_{this}; -}; - -} // namespace reading_list_infobar_overlay - -#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_INFOBAR_MODAL_OVERLAY_REQUEST_CALLBACK_INSTALLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.mm deleted file mode 100644 index 2c41a2af..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.mm +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.h" - -#include "base/bind.h" -#include "ios/chrome/browser/infobars/infobar_ios.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h" -#include "ios/chrome/browser/infobars/overlays/infobar_overlay_util.h" -#import "ios/chrome/browser/overlays/public/infobar_modal/reading_list_modal_overlay_request_config.h" -#import "ios/chrome/browser/overlays/public/infobar_modal/reading_list_modal_overlay_responses.h" -#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h" -#import "ios/chrome/browser/overlays/public/overlay_response.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -using reading_list_infobar_modal_responses::NeverAsk; - -namespace reading_list_infobar_overlay { - -ModalRequestCallbackInstaller::ModalRequestCallbackInstaller( - ReadingListInfobarModalInteractionHandler* interaction_handler) - : InfobarModalOverlayRequestCallbackInstaller( - ReadingListInfobarModalOverlayRequestConfig::RequestSupport(), - interaction_handler), - interaction_handler_(interaction_handler) { - DCHECK(interaction_handler_); -} - -ModalRequestCallbackInstaller::~ModalRequestCallbackInstaller() = default; - -#pragma mark - Private - -void ModalRequestCallbackInstaller::NeverAskCallback( - OverlayRequest* request, - OverlayResponse* response) { - InfoBarIOS* infobar = GetOverlayRequestInfobar(request); - if (!infobar) - return; - - interaction_handler_->NeverAsk(infobar); -} - -#pragma mark - OverlayRequestCallbackInstaller - -void ModalRequestCallbackInstaller::InstallCallbacksInternal( - OverlayRequest* request) { - InfobarModalOverlayRequestCallbackInstaller::InstallCallbacksInternal( - request); - OverlayCallbackManager* manager = request->GetCallbackManager(); - - manager->AddDispatchCallback(OverlayDispatchCallback( - base::BindRepeating(&ModalRequestCallbackInstaller::NeverAskCallback, - weak_factory_.GetWeakPtr(), request), - NeverAsk::ResponseSupport())); -} - -} // namespace reading_list_infobar_overlay
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer_unittest.mm deleted file mode 100644 index bc8f709..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer_unittest.mm +++ /dev/null
@@ -1,108 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.h" - -#include "base/test/task_environment.h" -#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/infobars/infobar_ios.h" -#include "ios/chrome/browser/infobars/infobar_manager_impl.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.h" -#import "ios/chrome/browser/main/test_browser.h" -#import "ios/chrome/browser/overlays/public/infobar_modal/infobar_modal_overlay_responses.h" -#import "ios/chrome/browser/overlays/public/infobar_modal/reading_list_modal_overlay_request_config.h" -#import "ios/chrome/browser/overlays/public/infobar_modal/reading_list_modal_overlay_responses.h" -#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h" -#include "ios/chrome/browser/overlays/public/overlay_request.h" -#include "ios/chrome/browser/overlays/public/overlay_request_queue.h" -#include "ios/chrome/browser/overlays/public/overlay_response.h" -#import "ios/chrome/browser/reading_list/fake_reading_list_model.h" -#import "ios/web/public/test/fakes/fake_navigation_manager.h" -#import "ios/web/public/test/fakes/fake_web_state.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/platform_test.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// Test fixture for TranslateInfobarModalOverlayRequestCallbackInstaller. -class ReadingListInfobarModalOverlayRequestCallbackInstallerTest - : public PlatformTest { - public: - ReadingListInfobarModalOverlayRequestCallbackInstallerTest() { - browser_state_ = TestChromeBrowserState::Builder().Build(); - browser_ = std::make_unique<TestBrowser>(browser_state_.get()); - mock_handler_ = - std::make_unique<MockReadingListInfobarModalInteractionHandler>( - browser_.get()); - installer_ = std::make_unique< - reading_list_infobar_overlay::ModalRequestCallbackInstaller>( - mock_handler_.get()); - // Create the infobar and add it to the WebState's manager. - web_state_.SetNavigationManager( - std::make_unique<web::FakeNavigationManager>()); - InfoBarManagerImpl::CreateForWebState(&web_state_); - fake_reading_list_model_ = std::make_unique<FakeReadingListModel>(); - std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>( - InfobarType::kInfobarTypeAddToReadingList, - std::make_unique<MockIOSAddToReadingListInfobarDelegate>( - fake_reading_list_model_.get(), &web_state_)); - - infobar_ = infobar.get(); - manager()->AddInfoBar(std::move(infobar)); - // Create the request and add it to the WebState's queue. - std::unique_ptr<OverlayRequest> added_request = - OverlayRequest::CreateWithConfig< - ReadingListInfobarModalOverlayRequestConfig>(infobar_); - request_ = added_request.get(); - queue()->AddRequest(std::move(added_request)); - // Install the callbacks on the added request. - installer_->InstallCallbacks(request_); - } - - void TearDown() override { - manager()->ShutDown(); - PlatformTest::TearDown(); - } - - InfoBarManagerImpl* manager() { - return InfoBarManagerImpl::FromWebState(&web_state_); - } - OverlayRequestQueue* queue() { - return OverlayRequestQueue::FromWebState(&web_state_, - OverlayModality::kInfobarModal); - } - - protected: - base::test::TaskEnvironment task_environment_; - std::unique_ptr<TestChromeBrowserState> browser_state_; - std::unique_ptr<TestBrowser> browser_; - web::FakeWebState web_state_; - std::unique_ptr<FakeReadingListModel> fake_reading_list_model_; - InfoBarIOS* infobar_ = nullptr; - OverlayRequest* request_ = nullptr; - std::unique_ptr<MockReadingListInfobarModalInteractionHandler> mock_handler_; - std::unique_ptr<reading_list_infobar_overlay::ModalRequestCallbackInstaller> - installer_; -}; - -// Tests that dispatching the NeverAsk Overlay response calls the NeverAsk() -// InteractionHandler method. -TEST_F(ReadingListInfobarModalOverlayRequestCallbackInstallerTest, NeverAsk) { - EXPECT_CALL(*mock_handler_, NeverAsk(infobar_)); - request_->GetCallbackManager()->DispatchResponse( - OverlayResponse::CreateWithInfo< - reading_list_infobar_modal_responses::NeverAsk>()); -} - -// Tests that dispatching the InfobarModalMainActionResponse Overlay response -// calls the PerformMainAction() InteractionHandler method. -TEST_F(ReadingListInfobarModalOverlayRequestCallbackInstallerTest, - PerformMainAction) { - EXPECT_CALL(*mock_handler_, PerformMainAction(infobar_)); - request_->GetCallbackManager()->DispatchResponse( - OverlayResponse::CreateWithInfo<InfobarModalMainActionResponse>()); -}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h deleted file mode 100644 index 05a5afca..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2021 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_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_MODAL_INFOBAR_INTERACTION_HANDLER_H_ -#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_MODAL_INFOBAR_INTERACTION_HANDLER_H_ - -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h" - -class IOSAddToReadingListInfobarDelegate; -class Browser; - -// Helper object that updates the model layer for interaction events with the -// Reading List infobar modal UI. -class ReadingListInfobarModalInteractionHandler - : public InfobarModalInteractionHandler { - public: - ReadingListInfobarModalInteractionHandler(Browser* browser); - ~ReadingListInfobarModalInteractionHandler() override; - - // Instructs the handler that the user has used |infobar|'s modal UI to - // request that the Reading List banner never be shown. - virtual void NeverAsk(InfoBarIOS* infobar); - - // InfobarModalInteractionHandler: - void PerformMainAction(InfoBarIOS* infobar) override; - - // InfobarInteractionHandler::Handler: - void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override; - - private: - // InfobarModalInteractionHandler: - std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> - CreateModalInstaller() override; - - IOSAddToReadingListInfobarDelegate* GetDelegate(InfoBarIOS* infobar); - - Browser* browser_; -}; - -#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_READING_LIST_ADD_TO_READING_LIST_MODAL_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.mm deleted file mode 100644 index 3d18db0..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.mm +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h" - -#include "ios/chrome/browser/infobars/infobar_ios.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_infobar_modal_overlay_request_callback_installer.h" -#import "ios/chrome/browser/main/browser.h" -#import "ios/chrome/browser/ui/commands/browser_commands.h" -#import "ios/chrome/browser/ui/commands/command_dispatcher.h" -#import "ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -using reading_list_infobar_overlay::ModalRequestCallbackInstaller; - -ReadingListInfobarModalInteractionHandler:: - ReadingListInfobarModalInteractionHandler(Browser* browser) - : browser_(browser) {} - -ReadingListInfobarModalInteractionHandler:: - ~ReadingListInfobarModalInteractionHandler() = default; - -#pragma mark - Public - -void ReadingListInfobarModalInteractionHandler::NeverAsk(InfoBarIOS* infobar) { - IOSAddToReadingListInfobarDelegate* delegate = GetDelegate(infobar); - delegate->NeverShow(); - - // Remove infobar. - infobar->RemoveSelf(); -} - -#pragma mark - InfobarModalInteractionHandler - -void ReadingListInfobarModalInteractionHandler::PerformMainAction( - InfoBarIOS* infobar) { - IOSAddToReadingListInfobarDelegate* delegate = GetDelegate(infobar); - infobar->set_accepted(delegate->Accept()); - [static_cast<id<BrowserCommands>>(browser_->GetCommandDispatcher()) - showReadingListIPH]; -} - -void ReadingListInfobarModalInteractionHandler::InfobarVisibilityChanged( - InfoBarIOS* infobar, - bool visible) { - if (!visible) { - GetDelegate(infobar)->InfoBarDismissed(); - } -} - -#pragma mark - Private - -std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> -ReadingListInfobarModalInteractionHandler::CreateModalInstaller() { - return std::make_unique<ModalRequestCallbackInstaller>(this); -} - -IOSAddToReadingListInfobarDelegate* -ReadingListInfobarModalInteractionHandler::GetDelegate(InfoBarIOS* infobar) { - IOSAddToReadingListInfobarDelegate* delegate = - IOSAddToReadingListInfobarDelegate::FromInfobarDelegate( - infobar->delegate()); - DCHECK(delegate); - return delegate; -}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler_unittest.mm deleted file mode 100644 index 402c2fc..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler_unittest.mm +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h" - -#include "base/test/task_environment.h" -#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/infobars/infobar_manager_impl.h" -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h" -#import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h" -#include "ios/chrome/browser/infobars/overlays/infobar_overlay_util.h" -#import "ios/chrome/browser/infobars/test/fake_infobar_ios.h" -#import "ios/chrome/browser/main/test_browser.h" -#import "ios/chrome/browser/overlays/public/overlay_request_queue.h" -#import "ios/chrome/browser/reading_list/fake_reading_list_model.h" -#import "ios/chrome/browser/ui/commands/browser_commands.h" -#import "ios/chrome/browser/ui/commands/command_dispatcher.h" -#import "ios/web/public/test/fakes/fake_navigation_manager.h" -#import "ios/web/public/test/fakes/fake_web_state.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#include "third_party/ocmock/gtest_support.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// Test fixture for ReadingListInfobarModalInteractionHandler. -class ReadingListInfobarModalInteractionHandlerTest : public PlatformTest { - public: - ReadingListInfobarModalInteractionHandlerTest() { - browser_state_ = TestChromeBrowserState::Builder().Build(); - browser_ = std::make_unique<TestBrowser>(browser_state_.get()); - mock_command_receiver_ = OCMStrictProtocolMock(@protocol(BrowserCommands)); - handler_ = std::make_unique<ReadingListInfobarModalInteractionHandler>( - browser_.get()); - web_state_.SetNavigationManager( - std::make_unique<web::FakeNavigationManager>()); - InfobarOverlayRequestInserter::CreateForWebState(&web_state_); - InfoBarManagerImpl::CreateForWebState(&web_state_); - fake_reading_list_model_ = std::make_unique<FakeReadingListModel>(); - - [browser_->GetCommandDispatcher() - startDispatchingToTarget:mock_command_receiver_ - forProtocol:@protocol(BrowserCommands)]; - - std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>( - InfobarType::kInfobarTypeAddToReadingList, - std::make_unique<MockIOSAddToReadingListInfobarDelegate>( - fake_reading_list_model_.get(), &web_state_)); - infobar_ = infobar.get(); - InfoBarManagerImpl::FromWebState(&web_state_) - ->AddInfoBar(std::move(infobar)); - } - - void TearDown() override { - [browser_->GetCommandDispatcher() - stopDispatchingToTarget:mock_command_receiver_]; - EXPECT_OCMOCK_VERIFY(mock_command_receiver_); - PlatformTest::TearDown(); - } - - MockIOSAddToReadingListInfobarDelegate& mock_delegate() { - return *static_cast<MockIOSAddToReadingListInfobarDelegate*>( - infobar_->delegate()); - } - - protected: - base::test::TaskEnvironment task_environment_; - std::unique_ptr<TestChromeBrowserState> browser_state_; - std::unique_ptr<TestBrowser> browser_; - id mock_command_receiver_ = nil; - std::unique_ptr<ReadingListInfobarModalInteractionHandler> handler_; - web::FakeWebState web_state_; - std::unique_ptr<FakeReadingListModel> fake_reading_list_model_; - InfoBarIOS* infobar_; -}; - -// Tests MainButtonTapped() calls Accept() on the mock delegate and resets -// the infobar to be accepted. -TEST_F(ReadingListInfobarModalInteractionHandlerTest, MainButton) { - ASSERT_FALSE(infobar_->accepted()); - EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true)); - OCMExpect([mock_command_receiver_ showReadingListIPH]); - handler_->PerformMainAction(infobar_); - EXPECT_TRUE(infobar_->accepted()); -} - -// Tests NeverAsk() calls proper delegate methods. -TEST_F(ReadingListInfobarModalInteractionHandlerTest, NeverAsk) { - EXPECT_CALL(mock_delegate(), NeverShow()).Times(1); - handler_->NeverAsk(infobar_); -}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn index c8717899..43f95c79 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn
@@ -11,10 +11,6 @@ "mock_autofill_save_update_address_profile_delegate_ios.mm", "mock_infobar_interaction_handler.h", "mock_infobar_interaction_handler.mm", - "mock_ios_add_to_reading_list_infobar_delegate.h", - "mock_ios_add_to_reading_list_infobar_delegate.mm", - "mock_reading_list_infobar_interaction_handler.h", - "mock_reading_list_infobar_interaction_handler.mm", "mock_save_address_profile_modal_infobar_interaction_handler.h", "mock_save_address_profile_modal_infobar_interaction_handler.mm", "mock_save_card_banner_infobar_interaction_handler.h", @@ -37,7 +33,6 @@ "//ios/chrome/browser/infobars/overlays", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile", - "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate", "//ios/chrome/browser/main:test_support", @@ -45,7 +40,6 @@ "//ios/chrome/browser/overlays/public/common/infobars", "//ios/chrome/browser/overlays/public/infobar_banner", "//ios/chrome/browser/overlays/test", - "//ios/chrome/browser/ui/reading_list:infobar", "//ios/web/public/test/fakes", "//testing/gmock", "//testing/gtest",
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h deleted file mode 100644 index 30796e26..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2021 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_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_IOS_ADD_TO_READING_LIST_INFOBAR_DELEGATE_H_ -#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_IOS_ADD_TO_READING_LIST_INFOBAR_DELEGATE_H_ - -#import "ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.h" - -#include "testing/gmock/include/gmock/gmock.h" - -class MockIOSAddToReadingListInfobarDelegate - : public IOSAddToReadingListInfobarDelegate { - public: - MockIOSAddToReadingListInfobarDelegate(ReadingListModel* model, - web::WebState* web_state); - ~MockIOSAddToReadingListInfobarDelegate() override; - - MOCK_METHOD0(Accept, bool()); - MOCK_METHOD0(NeverShow, void()); -}; - -#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_IOS_ADD_TO_READING_LIST_INFOBAR_DELEGATE_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.mm deleted file mode 100644 index 7b15418..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.mm +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_ios_add_to_reading_list_infobar_delegate.h" - -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -MockIOSAddToReadingListInfobarDelegate::MockIOSAddToReadingListInfobarDelegate( - ReadingListModel* model, - web::WebState* web_state) - : IOSAddToReadingListInfobarDelegate(GURL("http://www.test.com"), - std::u16string(), - 0, - 0, - 0, - model, - web_state) {} - -MockIOSAddToReadingListInfobarDelegate:: - ~MockIOSAddToReadingListInfobarDelegate() = default;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.h deleted file mode 100644 index d707095..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2021 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_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_READING_LIST_INFOBAR_INTERACTION_HANDLER_H_ -#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_READING_LIST_INFOBAR_INTERACTION_HANDLER_H_ - -#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list/add_to_reading_list_modal_infobar_interaction_handler.h" - -#include "testing/gmock/include/gmock/gmock.h" - -class InfoBarIOS; -class Browser; - -// Mock version of ReadingListInfobarModalInteractionHandler for use in tests. -class MockReadingListInfobarModalInteractionHandler - : public ReadingListInfobarModalInteractionHandler { - public: - MockReadingListInfobarModalInteractionHandler(Browser* browser); - ~MockReadingListInfobarModalInteractionHandler(); - - MOCK_METHOD1(NeverAsk, void(InfoBarIOS* infobar)); - MOCK_METHOD1(PerformMainAction, void(InfoBarIOS* infobar)); -}; - -#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_READING_LIST_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.mm deleted file mode 100644 index 120312c9..0000000 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.mm +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_reading_list_infobar_interaction_handler.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -MockReadingListInfobarModalInteractionHandler:: - MockReadingListInfobarModalInteractionHandler(Browser* browser) - : ReadingListInfobarModalInteractionHandler(browser) {} - -MockReadingListInfobarModalInteractionHandler:: - ~MockReadingListInfobarModalInteractionHandler() = default;
diff --git a/ios/chrome/browser/policy/BUILD.gn b/ios/chrome/browser/policy/BUILD.gn index 78c6cd0..d183698 100644 --- a/ios/chrome/browser/policy/BUILD.gn +++ b/ios/chrome/browser/policy/BUILD.gn
@@ -20,6 +20,10 @@ "chrome_browser_cloud_management_controller_observer_bridge.mm", "client_data_delegate_ios.cc", "client_data_delegate_ios.h", + "cloud/user_policy_signin_service.h", + "cloud/user_policy_signin_service.mm", + "cloud/user_policy_signin_service_factory.h", + "cloud/user_policy_signin_service_factory.mm", "cloud_policy_client_observer_bridge.h", "cloud_policy_client_observer_bridge.mm", "configuration_policy_handler_list_factory.h", @@ -52,17 +56,20 @@ deps = [ ":policy_util", "//base", + "//components/account_id", "//components/autofill/core/browser", "//components/bookmarks/common", "//components/bookmarks/managed", "//components/enterprise", "//components/history/core/common", + "//components/keyed_service/ios", "//components/metrics", "//components/optimization_guide/core", "//components/password_manager/core/common", "//components/policy:generated", "//components/policy/core/common", "//components/policy/proto", + "//components/pref_registry", "//components/safe_browsing/core/common:safe_browsing_policy_handler", "//components/safe_browsing/core/common:safe_browsing_prefs", "//components/search_engines", @@ -176,6 +183,7 @@ "browser_dm_token_storage_ios_unittest.mm", "browser_signin_policy_handler_unittest.mm", "client_data_delegate_ios_unittest.cc", + "cloud/user_policy_signin_service_unittest.mm", "new_tab_page_location_policy_handler_unittest.cc", "policy_unittest.mm", "policy_watcher_browser_agent_unittest.mm", @@ -192,13 +200,17 @@ ":test_support", "//base", "//base/test:test_support", + "//components/account_id", "//components/enterprise", "//components/enterprise:test_support", "//components/policy/core/browser:test_support", + "//components/policy/core/common", "//components/pref_registry", "//components/prefs", + "//components/signin/public/identity_manager:test_support", "//components/sync_preferences", "//components/sync_preferences:test_support", + "//google_apis", "//ios/chrome/app/application_delegate:app_state_header", "//ios/chrome/browser:chrome_paths", "//ios/chrome/browser:pref_names", @@ -217,6 +229,9 @@ "//ios/public/provider/chrome/browser/signin:fake_chrome_identity", "//ios/public/provider/chrome/browser/signin:test_support", "//ios/web/public/test:test", + "//net", + "//services/network:test_support", + "//services/network/public/cpp", "//testing/gtest", "//third_party/ocmock", ]
diff --git a/ios/chrome/browser/policy/browser_state_policy_connector.h b/ios/chrome/browser/policy/browser_state_policy_connector.h index e934a264..b5330bdc 100644 --- a/ios/chrome/browser/policy/browser_state_policy_connector.h +++ b/ios/chrome/browser/policy/browser_state_policy_connector.h
@@ -32,7 +32,8 @@ // Initializes this connector. void Init(policy::SchemaRegistry* schema_registry, - BrowserPolicyConnectorIOS* browser_policy_connector); + BrowserPolicyConnectorIOS* browser_policy_connector, + policy::ConfigurationPolicyProvider* user_policy_provider); // Shuts this connector down in preparation for destruction. void Shutdown();
diff --git a/ios/chrome/browser/policy/browser_state_policy_connector.mm b/ios/chrome/browser/policy/browser_state_policy_connector.mm index b81dd2829..06174057 100644 --- a/ios/chrome/browser/policy/browser_state_policy_connector.mm +++ b/ios/chrome/browser/policy/browser_state_policy_connector.mm
@@ -17,7 +17,8 @@ void BrowserStatePolicyConnector::Init( policy::SchemaRegistry* schema_registry, - BrowserPolicyConnectorIOS* browser_policy_connector) { + BrowserPolicyConnectorIOS* browser_policy_connector, + policy::ConfigurationPolicyProvider* user_policy_provider) { schema_registry_ = schema_registry; // The object returned by GetPlatformConnector() may or may not be in the list @@ -37,6 +38,11 @@ } } + // Put `user_policy_provider` at the end of the list because it is the + // provider with the lowest priority. + if (user_policy_provider) + policy_providers_.push_back(user_policy_provider); + policy_service_ = std::make_unique<policy::PolicyServiceImpl>(policy_providers_); }
diff --git a/ios/chrome/browser/policy/browser_state_policy_connector_factory.h b/ios/chrome/browser/policy/browser_state_policy_connector_factory.h index 14a408a..37ab3d6 100644 --- a/ios/chrome/browser/policy/browser_state_policy_connector_factory.h +++ b/ios/chrome/browser/policy/browser_state_policy_connector_factory.h
@@ -12,10 +12,12 @@ namespace policy { class SchemaRegistry; +class ConfigurationPolicyProvider; } // namespace policy std::unique_ptr<BrowserStatePolicyConnector> BuildBrowserStatePolicyConnector( policy::SchemaRegistry* schema_registry, - BrowserPolicyConnectorIOS* browser_policy_connector); + BrowserPolicyConnectorIOS* browser_policy_connector, + policy::ConfigurationPolicyProvider* user_policy_provider); #endif // IOS_CHROME_BROWSER_POLICY_BROWSER_STATE_POLICY_CONNECTOR_FACTORY_H_
diff --git a/ios/chrome/browser/policy/browser_state_policy_connector_factory.mm b/ios/chrome/browser/policy/browser_state_policy_connector_factory.mm index 418df7d..4ba4c17 100644 --- a/ios/chrome/browser/policy/browser_state_policy_connector_factory.mm +++ b/ios/chrome/browser/policy/browser_state_policy_connector_factory.mm
@@ -14,7 +14,8 @@ std::unique_ptr<BrowserStatePolicyConnector> BuildBrowserStatePolicyConnector( policy::SchemaRegistry* schema_registry, - BrowserPolicyConnectorIOS* browser_policy_connector) { + BrowserPolicyConnectorIOS* browser_policy_connector, + policy::ConfigurationPolicyProvider* user_policy_provider) { DCHECK(IsEnterprisePolicyEnabled()); auto connector = std::make_unique<BrowserStatePolicyConnector>(); @@ -24,6 +25,7 @@ // |browser_policy_connector|, despite being a separate instance. The two // levels of registry (owned by ApplicationContext vs owned by BrowserState) // are maintained to keep a parallel structure with Desktop. - connector->Init(schema_registry, browser_policy_connector); + connector->Init(schema_registry, browser_policy_connector, + user_policy_provider); return connector; }
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service.h b/ios/chrome/browser/policy/cloud/user_policy_signin_service.h new file mode 100644 index 0000000..1ab886b4 --- /dev/null +++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -0,0 +1,69 @@ +// Copyright 2022 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_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_H_ +#define IOS_CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_H_ + +#include <memory> + +#include "base/memory/raw_ptr.h" +#include "base/scoped_observation.h" +#include "components/policy/core/browser/cloud/user_policy_signin_service_base.h" +#include "components/signin/public/identity_manager/identity_manager.h" + +class ChromeBrowserState; + +namespace policy { + +class CloudPolicyClientRegistrationHelper; + +// A specialization of UserPolicySigninServiceBase for iOS. +class UserPolicySigninService : public UserPolicySigninServiceBase, + public signin::IdentityManager::Observer { + public: + // Creates a UserPolicySigninService associated with the |browser_state|. + UserPolicySigninService( + PrefService* browser_state_prefs, + PrefService* local_state, + DeviceManagementService* device_management_service, + UserCloudPolicyManager* policy_manager, + signin::IdentityManager* identity_manager, + scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory); + UserPolicySigninService(const UserPolicySigninService&) = delete; + UserPolicySigninService& operator=(const UserPolicySigninService&) = delete; + ~UserPolicySigninService() override; + + // signin::IdentityManager::Observer implementation: + void OnPrimaryAccountChanged( + const signin::PrimaryAccountChangeEvent& event) override; + + // KeyedService implementation: + void Shutdown() override; + + private: + // UserPolicySigninServiceBase implementation: + base::TimeDelta GetTryRegistrationDelay() override; + void ProhibitSignoutIfNeeded() override; + void UpdateLastPolicyCheckTime() override; + signin::ConsentLevel GetConsentLevelForRegistration() override; + bool CanApplyPolicies(bool check_for_refresh_token) override; + + // Tries to initialize the service if a signed in account is available and + // eligible for user policy. + void TryInitialize(); + + // Helper used to register for user policy. + std::unique_ptr<CloudPolicyClientRegistrationHelper> registration_helper_; + + // The PrefService associated with the BrowserState. + raw_ptr<PrefService> browser_state_prefs_; + + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + scoped_identity_manager_observation_{this}; +}; + +} // namespace policy + +#endif // IOS_CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_H_
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm b/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm new file mode 100644 index 0000000..cdfb0eca --- /dev/null +++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm
@@ -0,0 +1,119 @@ +// Copyright 2022 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 "ios/chrome/browser/policy/cloud/user_policy_signin_service.h" + +#include "base/logging.h" +#include "base/time/time.h" +#include "components/policy/core/browser/cloud/user_policy_signin_service_util.h" +#include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/prefs/pref_service.h" +#include "components/signin/public/base/consent_level.h" +#include "components/signin/public/identity_manager/identity_manager.h" +#include "components/signin/public/identity_manager/primary_account_change_event.h" +#include "google_apis/gaia/core_account_id.h" +#include "google_apis/gaia/gaia_auth_util.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// TODO(crbug.com/1312552): Move +// chrome/browser/signin/account_id_from_account_info.h to components/ to be +// able to reuse the helper here. +// +// Gets the AccountId from the provided |account_info|. +AccountId AccountIdFromAccountInfo(const CoreAccountInfo& account_info) { + if (account_info.email.empty() || account_info.gaia.empty()) + return EmptyAccountId(); + + return AccountId::FromUserEmailGaiaId( + gaia::CanonicalizeEmail(account_info.email), account_info.gaia); +} + +} // namespace + +namespace policy { + +UserPolicySigninService::UserPolicySigninService( + PrefService* browser_state_prefs, + PrefService* local_state, + DeviceManagementService* device_management_service, + UserCloudPolicyManager* policy_manager, + signin::IdentityManager* identity_manager, + scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory) + : UserPolicySigninServiceBase(local_state, + device_management_service, + policy_manager, + identity_manager, + system_url_loader_factory), + browser_state_prefs_(browser_state_prefs) { + TryInitialize(); +} + +UserPolicySigninService::~UserPolicySigninService() {} + +void UserPolicySigninService::Shutdown() { + scoped_identity_manager_observation_.Reset(); + CancelPendingRegistration(); + UserPolicySigninServiceBase::Shutdown(); +} + +void UserPolicySigninService::OnPrimaryAccountChanged( + const signin::PrimaryAccountChangeEvent& event) { + if (IsTurnOffSyncEvent(event)) { + ShutdownUserCloudPolicyManager(); + } +} + +void UserPolicySigninService::TryInitialize() { + // If using a TestingProfile with no IdentityManager or + // UserCloudPolicyManager, skip initialization. + if (!policy_manager() || !identity_manager()) { + DVLOG(1) << "Skipping initialization for tests due to missing components."; + return; + } + + // Shutdown the UserCloudPolicyManager when the user signs out. We start + // observing the IdentityManager here because we don't want to get signout + // notifications until after the profile has started initializing + // (http://crbug.com/316229). + scoped_identity_manager_observation_.Observe(identity_manager()); + + if (!CanApplyPolicies(/*check_for_refresh_token=*/false)) { + ShutdownUserCloudPolicyManager(); + return; + } + AccountId account_id = + AccountIdFromAccountInfo(identity_manager()->GetPrimaryAccountInfo( + GetConsentLevelForRegistration())); + InitializeForSignedInUser(account_id, system_url_loader_factory()); +} + +bool UserPolicySigninService::CanApplyPolicies(bool check_for_refresh_token) { + return CanApplyPoliciesForSignedInUser(check_for_refresh_token, + GetConsentLevelForRegistration(), + identity_manager()); +} + +base::TimeDelta UserPolicySigninService::GetTryRegistrationDelay() { + return GetTryRegistrationDelayFromPrefs(browser_state_prefs_); +} + +void UserPolicySigninService::ProhibitSignoutIfNeeded() {} + +void UserPolicySigninService::UpdateLastPolicyCheckTime() { + UpdateLastPolicyCheckTimeInPrefs(browser_state_prefs_); +} + +signin::ConsentLevel UserPolicySigninService::GetConsentLevelForRegistration() { + return signin::ConsentLevel::kSync; +} + +} // namespace policy
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.h b/ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.h new file mode 100644 index 0000000..c14fed8de --- /dev/null +++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.h
@@ -0,0 +1,62 @@ +// Copyright (c) 2022 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_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_FACTORY_H_ +#define IOS_CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/ios/browser_state_keyed_service_factory.h" + +namespace user_prefs { +class PrefRegistrySyncable; +} + +namespace web { +class BrowserState; +} + +namespace policy { + +class DeviceManagementService; +class UserPolicySigninService; + +// Singleton that owns all UserPolicySigninServices and creates/deletes them as +// new BrowserStates are created/shutdown. +class UserPolicySigninServiceFactory : public BrowserStateKeyedServiceFactory { + public: + // Returns an instance of the UserPolicySigninServiceFactory singleton. + static UserPolicySigninServiceFactory* GetInstance(); + + // Returns the instance of UserPolicySigninService for the |context|. + static UserPolicySigninService* GetForBrowserState( + web::BrowserState* context); + + // Allows setting a mock DeviceManagementService for tests. Does not take + // ownership, and should be reset to nullptr at the end of the test. + // Set this before an instance is built for a BrowserState. + static void SetDeviceManagementServiceForTesting( + DeviceManagementService* device_management_service); + + UserPolicySigninServiceFactory(const UserPolicySigninServiceFactory&) = + delete; + UserPolicySigninServiceFactory& operator=( + const UserPolicySigninServiceFactory&) = delete; + + protected: + // BrowserStateKeyedServiceFactory implementation: + std::unique_ptr<KeyedService> BuildServiceInstanceFor( + web::BrowserState* browser_state) const override; + void RegisterBrowserStatePrefs( + user_prefs::PrefRegistrySyncable* registry) override; + + private: + friend struct base::DefaultSingletonTraits<UserPolicySigninServiceFactory>; + + UserPolicySigninServiceFactory(); + ~UserPolicySigninServiceFactory() override; +}; + +} // namespace policy + +#endif // IOS_CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.mm b/ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.mm new file mode 100644 index 0000000..c5f1b78 --- /dev/null +++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.mm
@@ -0,0 +1,85 @@ +// Copyright 2022 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 "ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.h" + +#include "base/memory/ref_counted.h" +#include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/policy/browser_policy_connector_ios.h" +#include "ios/chrome/browser/policy/cloud/user_policy_signin_service.h" +#include "ios/chrome/browser/signin/identity_manager_factory.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +policy::DeviceManagementService* g_device_management_service_for_testing = NULL; + +} // namespace + +namespace policy { + +UserPolicySigninServiceFactory::UserPolicySigninServiceFactory() + : BrowserStateKeyedServiceFactory( + "UserPolicySigninService", + BrowserStateDependencyManager::GetInstance()) { + DependsOn(IdentityManagerFactory::GetInstance()); +} + +UserPolicySigninServiceFactory::~UserPolicySigninServiceFactory() {} + +// static +UserPolicySigninService* UserPolicySigninServiceFactory::GetForBrowserState( + web::BrowserState* context) { + return static_cast<UserPolicySigninService*>( + GetInstance()->GetServiceForBrowserState(context, true)); +} + +// static +UserPolicySigninServiceFactory* UserPolicySigninServiceFactory::GetInstance() { + return base::Singleton<UserPolicySigninServiceFactory>::get(); +} + +// static +void UserPolicySigninServiceFactory::SetDeviceManagementServiceForTesting( + DeviceManagementService* device_management_service) { + g_device_management_service_for_testing = device_management_service; +} + +std::unique_ptr<KeyedService> +UserPolicySigninServiceFactory::BuildServiceInstanceFor( + web::BrowserState* browser_state) const { + BrowserPolicyConnector* connector = + GetApplicationContext()->GetBrowserPolicyConnector(); + DeviceManagementService* device_management_service = + g_device_management_service_for_testing + ? g_device_management_service_for_testing + : connector->device_management_service(); + + ChromeBrowserState* chrome_browser_state = + ChromeBrowserState::FromBrowserState(browser_state); + + return std::make_unique<UserPolicySigninService>( + chrome_browser_state->GetPrefs(), + GetApplicationContext()->GetLocalState(), device_management_service, + chrome_browser_state->GetUserCloudPolicyManager(), + IdentityManagerFactory::GetForBrowserState(chrome_browser_state), + browser_state->GetSharedURLLoaderFactory()); +} + +void UserPolicySigninServiceFactory::RegisterBrowserStatePrefs( + user_prefs::PrefRegistrySyncable* user_prefs) { + user_prefs->RegisterInt64Pref(policy_prefs::kLastPolicyCheckTime, 0); +} + +} // namespace policy
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm b/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm new file mode 100644 index 0000000..73ce007b --- /dev/null +++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm
@@ -0,0 +1,534 @@ +// Copyright 2022 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 <utility> + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/memory/raw_ptr.h" +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/browser/cloud/user_policy_signin_service_util.h" +#include "components/policy/core/common/cloud/cloud_external_data_manager.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" +#include "components/policy/core/common/cloud/mock_device_management_service.h" +#include "components/policy/core/common/cloud/mock_user_cloud_policy_store.h" +#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/policy/core/common/schema_registry.h" +#include "components/prefs/pref_service.h" +#include "components/signin/public/identity_manager/identity_test_environment.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "google_apis/gaia/gaia_constants.h" +#include "google_apis/gaia/gaia_urls.h" +#include "google_apis/gaia/google_service_auth_error.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#include "ios/chrome/browser/policy/browser_policy_connector_ios.h" +#include "ios/chrome/browser/policy/cloud/user_policy_signin_service.h" +#include "ios/chrome/browser/policy/cloud/user_policy_signin_service_factory.h" +#include "ios/chrome/browser/policy/device_management_service_configuration_ios.h" +#include "ios/chrome/browser/prefs/browser_prefs.h" +#include "ios/chrome/test/testing_application_context.h" +#include "ios/web/public/test/web_task_environment.h" +#include "net/base/net_errors.h" +#include "net/http/http_status_code.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_network_connection_tracker.h" +#include "services/network/test/test_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using testing::_; +using testing::AnyNumber; +using testing::Mock; +using testing::SaveArg; + +namespace policy { + +constexpr char kManagedTestUser[] = "testuser@test.com"; + +constexpr char kUnmanagedTestUser[] = "testuser@gmail.com"; + +constexpr char kHostedDomainResponse[] = R"( + { + "hd": "test.com" + })"; + +constexpr char kDmToken[] = "dm_token"; + +// Builds and returns a UserCloudPolicyManager for testing. +std::unique_ptr<UserCloudPolicyManager> BuildCloudPolicyManager() { + auto store = std::make_unique<MockUserCloudPolicyStore>(); + EXPECT_CALL(*store, Load()).Times(AnyNumber()); + + return std::make_unique<UserCloudPolicyManager>( + std::move(store), base::FilePath(), + /*cloud_external_data_manager=*/nullptr, + base::ThreadTaskRunnerHandle::Get(), + network::TestNetworkConnectionTracker::CreateGetter()); +} + +class UserPolicySigninServiceTest : public PlatformTest { + public: + UserPolicySigninServiceTest() + : test_account_id_(AccountId::FromUserEmailGaiaId( + kManagedTestUser, + signin::GetTestGaiaIdForEmail(kManagedTestUser))), + register_completed_(false) {} + + MOCK_METHOD1(OnPolicyRefresh, void(bool)); + + // Called when the user policy registration is completed. + void OnRegisterCompleted(const std::string& dm_token, + const std::string& client_id) { + register_completed_ = true; + dm_token_ = dm_token; + client_id_ = client_id; + } + + // Registers the `kManagedTestUser` for user policy. + void RegisterPolicyClientWithCallback(UserPolicySigninService* service) { + UserPolicySigninServiceBase::PolicyRegistrationCallback callback = + base::BindOnce(&UserPolicySigninServiceTest::OnRegisterCompleted, + base::Unretained(this)); + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kManagedTestUser); + service->RegisterForPolicyWithAccountId( + kManagedTestUser, account_info.account_id, std::move(callback)); + ASSERT_TRUE(IsRequestActive()); + } + + void SetUp() override { + device_management_service_.ScheduleInitialization(0); + base::RunLoop().RunUntilIdle(); + UserPolicySigninServiceFactory::SetDeviceManagementServiceForTesting( + &device_management_service_); + + local_state_ = std::make_unique<TestingPrefServiceSimple>(); + RegisterLocalStatePrefs(local_state_->registry()); + TestingApplicationContext::GetGlobal()->SetLocalState(local_state_.get()); + + TestingApplicationContext::GetGlobal()->GetBrowserPolicyConnector()->Init( + local_state_.get(), + TestingApplicationContext::GetGlobal()->GetSharedURLLoaderFactory()); + + auto prefs = + std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); + RegisterBrowserStatePrefs(prefs->registry()); + prefs->registry()->RegisterInt64Pref(policy_prefs::kLastPolicyCheckTime, 0); + + TestChromeBrowserState::Builder builder; + builder.SetPrefService( + std::unique_ptr<sync_preferences::PrefServiceSyncable>( + std::move(prefs))); + builder.SetUserCloudPolicyManager(BuildCloudPolicyManager()); + browser_state_ = builder.Build(); + browser_state_->SetSharedURLLoaderFactory( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)); + + manager_ = browser_state_->GetUserCloudPolicyManager(); + DCHECK(manager_); + manager_->Init(&schema_registry_); + mock_store_ = + static_cast<MockUserCloudPolicyStore*>(manager_->core()->store()); + DCHECK(mock_store_); + + // Verify that the UserCloudPolicyManager core services aren't initialized + // before creating the user policy service. + ASSERT_FALSE(manager_->core()->service()); + } + + void TearDown() override { + if (user_policy_signin_service_) { + user_policy_signin_service_->Shutdown(); + } + user_policy_signin_service_.reset(); + manager_->Shutdown(); + + UserPolicySigninServiceFactory::SetDeviceManagementServiceForTesting( + nullptr); + + browser_state_.reset(); + TestingApplicationContext::GetGlobal()->SetLocalState(nullptr); + local_state_.reset(); + TestingApplicationContext::GetGlobal() + ->GetBrowserPolicyConnector() + ->Shutdown(); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + } + + // Returns true if there is at least one request that is currently pending in + // the URL loader. + bool IsRequestActive() { + if (identity_test_env()->IsAccessTokenRequestPending()) + return true; + return test_url_loader_factory_.NumPending() > 0; + } + + // Makes the oauth token fetch that is pending a success. + void MakeOAuthTokenFetchSucceed() { + ASSERT_TRUE(IsRequestActive()); + identity_test_env() + ->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( + "access_token", base::Time::Now()); + } + + // Makes the oauth token fetch that is pending a failure. + void MakeOAuthTokenFetchFail() { + ASSERT_TRUE(identity_test_env()->IsAccessTokenRequestPending()); + identity_test_env() + ->WaitForAccessTokenRequestIfNecessaryAndRespondWithError( + GoogleServiceAuthError::FromServiceError("fail")); + } + + // Makes the user info request respond with the hosted domain info. Set + // `is_hosted_domain` to true to fill hosted domain info in the response. The + // response will be empty is set to false. + void ReportHostedDomainStatus(bool is_hosted_domain) { + ASSERT_TRUE(IsRequestActive()); + ASSERT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest( + GaiaUrls::GetInstance()->oauth_user_info_url().spec(), + is_hosted_domain ? kHostedDomainResponse : "{}")); + } + + // Simulates the flow that registrates an account for user policy. + void RegisterForPolicyAndSignin() { + EXPECT_CALL(*this, OnPolicyRefresh(true)).Times(0); + RegisterPolicyClientWithCallback(user_policy_signin_service_.get()); + + // Sign in to Chrome. + identity_test_env()->SetPrimaryAccount(kManagedTestUser, + signin::ConsentLevel::kSync); + + DoPendingRegistration(/*with_dm_token=*/true, + /*with_oauth_token_success=*/true); + + EXPECT_TRUE(register_completed_); + EXPECT_EQ(dm_token_, kDmToken); + } + + signin::IdentityTestEnvironment* identity_test_env() { + return &identity_test_env_; + } + + // Initialize the UserPolicySigninService by creating the instance of the + // service that is hold by `user_policy_signin_service_`. + void InitUserPolicySigninService() { + user_policy_signin_service_ = std::make_unique<UserPolicySigninService>( + browser_state_->GetPrefs(), local_state_.get(), + &device_management_service_, + browser_state_->GetUserCloudPolicyManager(), + identity_test_env_.identity_manager(), + browser_state_->GetSharedURLLoaderFactory()); + } + + // Does and complete the registration job that was queued and that is + // currently pending. + void DoPendingRegistration(bool with_dm_token, + bool with_oauth_token_success) { + if (with_oauth_token_success) { + MakeOAuthTokenFetchSucceed(); + } else { + MakeOAuthTokenFetchFail(); + ASSERT_FALSE(IsRequestActive()); + return; + } + + // When the user is from a hosted domain, this should kick off client + // registration. + DeviceManagementService::JobConfiguration::JobType job_type = + DeviceManagementService::JobConfiguration::TYPE_INVALID; + DeviceManagementService::JobForTesting job; + EXPECT_CALL(job_creation_handler_, OnJobCreation) + .WillOnce(DoAll(device_management_service_.CaptureJobType(&job_type), + SaveArg<0>(&job))); + + // Mimic the user being a hosted domain - this should cause a Register() + // call. + ReportHostedDomainStatus(true); + + // Should have no more outstanding requests. + ASSERT_FALSE(IsRequestActive()); + Mock::VerifyAndClearExpectations(this); + ASSERT_TRUE(job.IsActive()); + EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_REGISTRATION, + job_type); + + enterprise_management::DeviceManagementResponse registration_response; + if (with_dm_token) { + registration_response.mutable_register_response() + ->set_device_management_token(kDmToken); + registration_response.mutable_register_response()->set_enrollment_type( + enterprise_management::DeviceRegisterResponse::ENTERPRISE); + } + device_management_service_.SendJobOKNow(&job, registration_response); + } + + protected: + web::WebTaskEnvironment task_environment_{ + web::WebTaskEnvironment::Options::DEFAULT, + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + + std::unique_ptr<TestChromeBrowserState> browser_state_; + raw_ptr<MockUserCloudPolicyStore> mock_store_ = nullptr; // Not owned. + SchemaRegistry schema_registry_; + raw_ptr<UserCloudPolicyManager> manager_ = nullptr; // Not owned. + + // Used in conjunction with OnRegisterCompleted() to test client registration + // callbacks. + std::string dm_token_; + std::string client_id_; + + // AccountId for the test user. + AccountId test_account_id_; + + // True if OnRegisterCompleted() was called. + bool register_completed_; + + testing::StrictMock<MockJobCreationHandler> job_creation_handler_; + FakeDeviceManagementService device_management_service_{ + &job_creation_handler_}; + + std::unique_ptr<TestingPrefServiceSimple> local_state_; + network::TestURLLoaderFactory test_url_loader_factory_; + signin::IdentityTestEnvironment identity_test_env_; + std::unique_ptr<UserPolicySigninService> user_policy_signin_service_; +}; + +// Tests that the user policy manager isn't initialized when initializing the +// user policy service with a user that isn't syncing. +TEST_F(UserPolicySigninServiceTest, + DontRegisterDuringInitializationBecauseUserSignedOut) { + // Verify that the user isn't syncing before starting the user policy + // service. + ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( + signin::ConsentLevel::kSync)); + + // Initialize UserPolicySigninService without a syncing account which should + // result in shutting down the manager. + EXPECT_CALL(*mock_store_, Clear()); + InitUserPolicySigninService(); + Mock::VerifyAndClearExpectations(mock_store_); + + // Expect that the UserCloudPolicyManager isn't initialized because the user + // wasn't syncing, hence not eligible for user policy. + EXPECT_FALSE(manager_->core()->service()); +} + +// Tests that the user policy manager isn't initialized when initializing the +// user policy service with a user that is syncing with an unmanaged account +// that is not eligible for user policy. +TEST_F(UserPolicySigninServiceTest, + DontRegisterDuringInitializationBecauseUnmanagedAccount) { + // Set the user as signed in and syncing with an unmanaged account. + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kUnmanagedTestUser); + identity_test_env()->SetPrimaryAccount(kUnmanagedTestUser, + signin::ConsentLevel::kSync); + + // Initialize the UserPolicySigninService with a syncing account that is + // unmanaged which should result in shutting down the manager. + InitUserPolicySigninService(); + + // Expect that the UserCloudPolicyManager isn't initialized because the user + // was using an unmanaged account, hence not eligible for user policy. + EXPECT_FALSE(manager_->core()->service()); +} + +// Tests that the user policy manager isn't initialized when initializing the +// user policy service with a user that is signed in but not syncing. +TEST_F(UserPolicySigninServiceTest, + DontRegisterDuringInitializationBecauseSignedInButNotSynced) { + // Set the user as signed in with a managed account. + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kManagedTestUser); + identity_test_env()->SetPrimaryAccount(kManagedTestUser, + signin::ConsentLevel::kSignin); + + // Initialize UserPolicySigninService with a signed in account that is + // not syncing which should result in shutting down the manager. + EXPECT_CALL(*mock_store_, Clear()); + InitUserPolicySigninService(); + Mock::VerifyAndClearExpectations(mock_store_); + + // Expect that the UserCloudPolicyManager isn't initialized because the user + // was signed in with a managed account but not syncing, hence not eligible + // for user policy. + EXPECT_FALSE(manager_->core()->service()); +} + +// Tests that the registration for user policy and the initialization of the +// user policy manager can be done during the initialization of the user policy +// service when the user is already syncing and eligible for user policy. +TEST_F(UserPolicySigninServiceTest, + RegisterAndInitializeManagerDuringInitialization) { + // Set the user as signed in and syncing. + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kManagedTestUser); + identity_test_env()->SetPrimaryAccount(kManagedTestUser, + signin::ConsentLevel::kSync); + + // Mark the store as loaded to allow registration during the initialization of + // the user policy service. + mock_store_->NotifyStoreLoaded(); + + // Initialize the UserPolicySigninService while the user has sync enabled and + // is eligible for user policy. This will kick off the asynchronous + // registration process. + InitUserPolicySigninService(); + + // Run the delayed task to start the registration by fast forwarding the task + // runner clock. + task_environment_.FastForwardBy( + GetTryRegistrationDelayFromPrefs(browser_state_->GetPrefs())); + + // Do the pending registration that was queued in the initialization of the + // service. + DoPendingRegistration(/*with_dm_token=*/true, + /*with_oauth_token_success=*/true); + // Verify that the client is registered after the initialization. + ASSERT_TRUE(manager_->core()->client()->is_registered()); + + // Expect the UserCloudPolicyManager to be initialized when creating the + // service because the user is syncing and eligible for user policy. + EXPECT_EQ(mock_store_->signin_account_id(), test_account_id_); + ASSERT_TRUE(manager_->core()->service()); + + // Expect sign-out to clear the policy from the store and shutdown the + // UserCloudPolicyManager. + EXPECT_CALL(*mock_store_, Clear()); + identity_test_env()->ClearPrimaryAccount(); + ASSERT_FALSE(manager_->core()->service()); +} + +// Tests that registration is still possible after the manager was shutdown +// because of sign-out. +TEST_F(UserPolicySigninServiceTest, CanRegisterAfterSignOut) { + // Explicitly forcing this call is necessary for the clearing of the primary + // account to result in the account being fully removed in this testing + // context. + identity_test_env()->EnableRemovalOfExtendedAccountInfo(); + + // Set the user as signed in and syncing. + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kManagedTestUser); + identity_test_env()->SetPrimaryAccount(kManagedTestUser, + signin::ConsentLevel::kSync); + + // Mark the store as loaded to allow registration during the initialization of + // the user policy service. + mock_store_->NotifyStoreLoaded(); + + // Initialize the UserPolicySigninService while the user has sync enabled and + // is eligible for user policy. This will kick off the asynchronous + // registration process. + InitUserPolicySigninService(); + + // Register. + task_environment_.FastForwardBy( + GetTryRegistrationDelayFromPrefs(browser_state_->GetPrefs())); + DoPendingRegistration(/*with_dm_token=*/true, + /*with_oauth_token_success=*/true); + ASSERT_TRUE(manager_->core()->client()->is_registered()); + + // Expect the UserCloudPolicyManager to be initialized when creating the + // service because the user is syncing and eligible for user policy. + EXPECT_EQ(mock_store_->signin_account_id(), test_account_id_); + ASSERT_TRUE(manager_->core()->service()); + + // Sign out. This should shutdown the manager and clear the policy data store. + EXPECT_CALL(*mock_store_, Clear()); + identity_test_env()->ClearPrimaryAccount(); + ASSERT_FALSE(manager_->core()->service()); + + // Verify the registration can still be done. + RegisterForPolicyAndSignin(); + EXPECT_TRUE(register_completed_); + EXPECT_EQ(dm_token_, kDmToken); +} + +// Tests that registration errors can be handled. +TEST_F(UserPolicySigninServiceTest, CanHandleRegisterError) { + // Explicitly forcing this call is necessary for the clearing of the primary + // account to result in the account being fully removed in this testing + // context. + identity_test_env()->EnableRemovalOfExtendedAccountInfo(); + + // Set the user as signed in and syncing. + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kManagedTestUser); + identity_test_env()->SetPrimaryAccount(kManagedTestUser, + signin::ConsentLevel::kSync); + + // Mark the store as loaded to allow registration during the initialization of + // the user policy service. + mock_store_->NotifyStoreLoaded(); + + // Initialize the UserPolicySigninService while the user has sync enabled and + // is eligible for user policy. This will kick off the asynchronous + // registration process. + InitUserPolicySigninService(); + + // Register with failure. + task_environment_.FastForwardBy( + GetTryRegistrationDelayFromPrefs(browser_state_->GetPrefs())); + DoPendingRegistration(/*with_dm_token=*/false, + /*with_oauth_token_success=*/true); + + // Verify that the client doesn't declare itself as registered. + ASSERT_FALSE(manager_->core()->client()->is_registered()); + + // The manager should still be initialized despite the failed registration. + EXPECT_EQ(mock_store_->signin_account_id(), test_account_id_); + ASSERT_TRUE(manager_->core()->service()); +} + +// Tests that oauth token errors can be handled. +TEST_F(UserPolicySigninServiceTest, CanHandleOauthTokenError) { + // Explicitly forcing this call is necessary for the clearing of the primary + // account to result in the account being fully removed in this testing + // context. + identity_test_env()->EnableRemovalOfExtendedAccountInfo(); + + // Set the user as signed in and syncing. + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable(kManagedTestUser); + identity_test_env()->SetPrimaryAccount(kManagedTestUser, + signin::ConsentLevel::kSync); + + // Mark the store as loaded to allow registration during the initialization of + // the user policy service. + mock_store_->NotifyStoreLoaded(); + + // Initialize the UserPolicySigninService while the user has sync enabled and + // is eligible for user policy. This will kick off the asynchronous + // registration process. + InitUserPolicySigninService(); + + // Register with failure. + task_environment_.FastForwardBy( + GetTryRegistrationDelayFromPrefs(browser_state_->GetPrefs())); + DoPendingRegistration(/*with_dm_token=*/true, + /*with_oauth_token_success=*/false); + + // Verify that the client doesn't declare itself as registered. + ASSERT_FALSE(manager_->core()->client()->is_registered()); + + // The manager should still be initialized despite the failed registration. + EXPECT_EQ(mock_store_->signin_account_id(), test_account_id_); + ASSERT_TRUE(manager_->core()->service()); +} + +} // namespace policy
diff --git a/ios/chrome/browser/policy/enterprise_policy_test_helper.cc b/ios/chrome/browser/policy/enterprise_policy_test_helper.cc index e90da1f0..a21ad23 100644 --- a/ios/chrome/browser/policy/enterprise_policy_test_helper.cc +++ b/ios/chrome/browser/policy/enterprise_policy_test_helper.cc
@@ -43,7 +43,7 @@ std::make_unique<BrowserStatePolicyConnector>(); browser_state_policy_connector_->Init( browser_policy_connector_->GetSchemaRegistry(), - browser_policy_connector_.get()); + browser_policy_connector_.get(), /*user_policy_provider=*/nullptr); scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry( new user_prefs::PrefRegistrySyncable); RegisterBrowserStatePrefs(pref_registry.get());
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn index 40ed9fec..30c9e2c4 100644 --- a/ios/chrome/browser/prefs/BUILD.gn +++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -89,7 +89,6 @@ "//ios/chrome/browser/ui/content_suggestions", "//ios/chrome/browser/ui/first_run:field_trial", "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent", - "//ios/chrome/browser/ui/reading_list:features", "//ios/chrome/browser/ui/reading_list:reading_list_constants", "//ios/chrome/browser/voice:prefs", "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index 4175a19..3e80e331 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -73,8 +73,6 @@ #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h" #include "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_constants.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #include "ios/chrome/browser/voice/voice_search_prefs_registration.h" #import "ios/chrome/browser/web/font_size/font_size_tab_helper.h" #import "ios/web/common/features.h" @@ -139,6 +137,10 @@ const char kShowReadingListInBookmarkBar[] = "bookmark_bar.show_reading_list"; } +// Deprecated 03/2022 +const char kPrefReadingListMessagesNeverShow[] = + "reading_list_message_never_show"; + void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { BrowserStateInfoCache::RegisterPrefs(registry); flags_ui::PrefServiceFlagsStorage::RegisterPrefs(registry); @@ -312,10 +314,6 @@ registry->RegisterBooleanPref(kWasOnboardingFeatureCheckedBefore, false); registry->RegisterDictionaryPref(kDomainsWithCookiePref); - if (IsReadingListMessagesEnabled()) { - registry->RegisterBooleanPref(kPrefReadingListMessagesNeverShow, false); - } - registry->RegisterBooleanPref(prefs::kAllowChromeDataInBackups, true); // Preference related to the browser sign-in policy that is being deprecated. @@ -390,4 +388,9 @@ // Added 03/2022 prefs->ClearPref(kShowReadingListInBookmarkBar); + + // Added 3/2022. + if (prefs->FindPreference(kPrefReadingListMessagesNeverShow)) { + prefs->ClearPref(kPrefReadingListMessagesNeverShow); + } }
diff --git a/ios/chrome/browser/safe_browsing/verdict_cache_manager_factory.mm b/ios/chrome/browser/safe_browsing/verdict_cache_manager_factory.mm index f97b71ae..d35eb5c 100644 --- a/ios/chrome/browser/safe_browsing/verdict_cache_manager_factory.mm +++ b/ios/chrome/browser/safe_browsing/verdict_cache_manager_factory.mm
@@ -7,11 +7,14 @@ #include "base/no_destructor.h" #include "components/keyed_service/core/service_access_type.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/safe_browsing/core/browser/sync/safe_browsing_sync_observer_impl.h" #include "components/safe_browsing/core/browser/verdict_cache_manager.h" +#include "components/sync/driver/sync_service.h" #import "ios/chrome/browser/browser_state/browser_state_otr_helper.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" #import "ios/chrome/browser/history/history_service_factory.h" +#include "ios/chrome/browser/sync/sync_service_factory.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -49,7 +52,9 @@ chrome_browser_state, ServiceAccessType::EXPLICIT_ACCESS), ios::HostContentSettingsMapFactory::GetForBrowserState( chrome_browser_state), - chrome_browser_state->GetPrefs()); + chrome_browser_state->GetPrefs(), + std::make_unique<safe_browsing::SafeBrowsingSyncObserverImpl>( + SyncServiceFactory::GetForBrowserState(chrome_browser_state))); } web::BrowserState* VerdictCacheManagerFactory::GetBrowserStateToUse(
diff --git a/ios/chrome/browser/ui/follow/followed_web_channel.h b/ios/chrome/browser/ui/follow/followed_web_channel.h index ce5625a..74858481 100644 --- a/ios/chrome/browser/ui/follow/followed_web_channel.h +++ b/ios/chrome/browser/ui/follow/followed_web_channel.h
@@ -20,8 +20,11 @@ // URL of the web channel. @property(nonatomic, strong) CrURL* channelURL; -// YES if the web channel is unavailable. -@property(nonatomic, assign) BOOL unavailable; +// URL of the favicon. +@property(nonatomic, strong) CrURL* faviconURL; + +// YES if the web channel is available. +@property(nonatomic, assign) BOOL available; // Used to request to unfollow this web channel. @property(nonatomic, copy) FollowRequestBlock unfollowRequestBlock; @@ -29,10 +32,18 @@ // Used to request to refollow this web channel, if it has been unfollowed. @property(nonatomic, copy) FollowRequestBlock refollowRequestBlock; +// TODO(crbug.com/1296745): Remove old API. - (instancetype)initWithTitle:(NSString*)title crURL:(CrURL*)channelURL unavailable:(BOOL)unavailable unfollowRequestBlock:(FollowRequestBlock)unfollowRequestBlock + refollowRequestBlock:(FollowRequestBlock)refollowRequestBlock; + +- (instancetype)initWithTitle:(NSString*)title + channelURL:(CrURL*)channelURL + faviconURL:(CrURL*)faviconURL + available:(BOOL)available + unfollowRequestBlock:(FollowRequestBlock)unfollowRequestBlock refollowRequestBlock:(FollowRequestBlock)refollowRequestBlock NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/ui/follow/followed_web_channel.mm b/ios/chrome/browser/ui/follow/followed_web_channel.mm index e73d596..3c785ec 100644 --- a/ios/chrome/browser/ui/follow/followed_web_channel.mm +++ b/ios/chrome/browser/ui/follow/followed_web_channel.mm
@@ -10,16 +10,32 @@ @implementation FollowedWebChannel +// TODO(crbug.com/1296745): Remove old API. - (instancetype)initWithTitle:(NSString*)title crURL:(CrURL*)channelURL unavailable:(BOOL)unavailable unfollowRequestBlock:(FollowRequestBlock)unfollowRequestBlock refollowRequestBlock:(FollowRequestBlock)refollowRequestBlock { + return [self initWithTitle:title + channelURL:channelURL + faviconURL:nil + available:!unavailable + unfollowRequestBlock:unfollowRequestBlock + refollowRequestBlock:refollowRequestBlock]; +} + +- (instancetype)initWithTitle:(NSString*)title + channelURL:(CrURL*)channelURL + faviconURL:(CrURL*)faviconURL + available:(BOOL)available + unfollowRequestBlock:(FollowRequestBlock)unfollowRequestBlock + refollowRequestBlock:(FollowRequestBlock)refollowRequestBlock { self = [super init]; if (self) { _title = title; _channelURL = channelURL; - _unavailable = unavailable; + _faviconURL = faviconURL; + _available = available; _unfollowRequestBlock = unfollowRequestBlock; _refollowRequestBlock = refollowRequestBlock; }
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index 4e5c319..55fd8ca 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -79,21 +79,6 @@ frameworks = [ "UIKit.framework" ] } -source_set("reading_list_scene_agent") { - configs += [ "//build/config/compiler:enable_arc" ] - sources = [ - "reading_list_background_session_scene_agent.h", - "reading_list_background_session_scene_agent.mm", - ] - deps = [ - ":observing_scene_agent", - "//base", - "//ios/chrome/browser/ui/reading_list:features", - "//ios/chrome/browser/ui/reading_list:reading_list_constants", - ] - frameworks = [ "UIKit.framework" ] -} - source_set("scene") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ @@ -114,7 +99,6 @@ ":incognito_blocker_scene_agent", ":main", ":observing_scene_agent", - ":reading_list_scene_agent", ":scene_testing", "//base", "//base/ios", @@ -176,7 +160,6 @@ "//ios/chrome/browser/ui/history", "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent", "//ios/chrome/browser/ui/main:browser_interface_provider", - "//ios/chrome/browser/ui/reading_list:features", "//ios/chrome/browser/ui/scoped_ui_blocker", "//ios/chrome/browser/ui/settings:settings_root", "//ios/chrome/browser/ui/settings/sync",
diff --git a/ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.h b/ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.h deleted file mode 100644 index 127ed44..0000000 --- a/ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.h +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2021 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_BROWSER_UI_MAIN_READING_LIST_BACKGROUND_SESSION_SCENE_AGENT_H_ -#define IOS_CHROME_BROWSER_UI_MAIN_READING_LIST_BACKGROUND_SESSION_SCENE_AGENT_H_ - -#import "ios/chrome/browser/ui/main/observing_scene_state_agent.h" - -// A scene agent that resets an NSUserDefault property for the Add to Reading -// List Messages when a new browser session has been deemed to have started. -@interface ReadingListBackgroundSessionSceneAgent : ObservingSceneAgent -@end - -#endif // IOS_CHROME_BROWSER_UI_MAIN_READING_LIST_BACKGROUND_SESSION_SCENE_AGENT_H_
diff --git a/ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.mm b/ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.mm deleted file mode 100644 index d2ec415..0000000 --- a/ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.mm +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.h" - -#import "ios/chrome/browser/ui/reading_list/reading_list_constants.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -// NSUserDefault key to save the last time the app backgrounded. -NSString* const kReadingListLastBackgroundTime = - @"kReadingListLastBackgroundTime"; -// Minimum time threshold app is not in the foreground before the next app open -// can be deemed a new "session". Currently set to half an hour. -const NSTimeInterval kReadingListBackgroundThreshold = 60 * 30; -} // namespace - -@interface ReadingListBackgroundSessionSceneAgent () - -@end - -@implementation ReadingListBackgroundSessionSceneAgent - -#pragma mark - SceneStateObserver - -- (void)sceneState:(SceneState*)sceneState - transitionedToActivationLevel:(SceneActivationLevel)level { - if (!IsReadingListMessagesEnabled()) { - return; - } - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - if (level <= SceneActivationLevelBackground) { - // If the ApplicationState is not active, then that means no other scenes - // are in the foreground, meaning the app is completely backgrounded. - if (UIApplication.sharedApplication.applicationState != - UIApplicationStateActive) { - // Save the time when the app is backgrounded. - [defaults setObject:[NSDate date] forKey:kReadingListLastBackgroundTime]; - } - } else if (level == SceneActivationLevelForegroundInactive) { - NSDate* last_background_timestamp = - [defaults objectForKey:kReadingListLastBackgroundTime]; - if (!last_background_timestamp) { - // There may not be a saved time if the app crashes. It's ok that - // kLastTimeUserShownReadingListMessages is not reset in this situation. - return; - } - NSDate* half_hour_ago_date = - [NSDate dateWithTimeIntervalSinceNow:-kReadingListBackgroundThreshold]; - if ([last_background_timestamp compare:half_hour_ago_date] == - NSOrderedAscending) { - // Reset the last Messages prompt timestamp when it is the start of a new - // "session". - [defaults removeObjectForKey:kLastTimeUserShownReadingListMessages]; - if ([defaults boolForKey:kLastReadingListEntryAddedFromMessages]) { - // If there was a Reading List entry added in the last session, set - // flags to allow for Reading List unread count badges to animate. - [defaults removeObjectForKey:kLastReadingListEntryAddedFromMessages]; - [defaults setBool:YES - forKey:kShouldAnimateReadingListNTPUnreadCountBadge]; - [defaults - setBool:YES - forKey:kShouldAnimateReadingListOverflowMenuUnreadCountBadge]; - } - } - [defaults removeObjectForKey:kReadingListLastBackgroundTime]; - } -} - -@end
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index b95fc08f..f958d94f 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -97,7 +97,6 @@ #import "ios/chrome/browser/ui/main/browser_view_wrangler.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" #import "ios/chrome/browser/ui/main/incognito_blocker_scene_agent.h" -#import "ios/chrome/browser/ui/main/reading_list_background_session_scene_agent.h" #import "ios/chrome/browser/ui/main/signin_policy_scene_agent.h" #import "ios/chrome/browser/ui/main/ui_blocker_scene_agent.h" #import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h" @@ -294,8 +293,6 @@ initWithReauthModule:[[ReauthenticationModule alloc] init]]]; [_sceneState addAgent:[[StartSurfaceSceneAgent alloc] init]]; - [_sceneState - addAgent:[[ReadingListBackgroundSessionSceneAgent alloc] init]]; [_sceneState addAgent:[[SessionSavingSceneAgent alloc] init]]; } return self;
diff --git a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm index 0285900..145eb2a 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm +++ b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm
@@ -36,7 +36,7 @@ } - (NSString*)thirdRowText { - if (_followedWebChannel.unavailable) { + if (!_followedWebChannel.available) { return l10n_util::GetNSString( IDS_IOS_FOLLOW_MANAGEMENT_CHANNEL_UNAVAILABLE); }
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h index fae7014..8925446c 100644 --- a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h +++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h
@@ -41,9 +41,6 @@ // Title label for the cell. @property(nonatomic, strong, readonly) UILabel* titleLabel; -// Badge displaying a number. -@property(nonatomic, strong, readonly) UIView* numberBadgeView; - // Whether the cell is associated with a destructive action. If |YES|, then a // specific styling is applied. @property(nonatomic, assign) BOOL destructiveAction;
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.mm b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.mm index fead73d..b0230803 100644 --- a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.mm +++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.mm
@@ -84,8 +84,8 @@ @property(nonatomic, strong, readwrite) UILabel* titleLabel; // Image view for the cell, redefined as readwrite. @property(nonatomic, strong, readwrite) UIImageView* imageView; -// Internal implementation of |numberBadgeView|. -@property(nonatomic, strong) NumberBadgeView* numberBadgeViewImpl; +// Badge displaying a number. +@property(nonatomic, strong) NumberBadgeView* numberBadgeView; // Badge displaying text. @property(nonatomic, strong) TextBadgeView* textBadgeView; // Constraints between the trailing of the label and the badges. @@ -129,8 +129,8 @@ _imageView = [[UIImageView alloc] init]; _imageView.translatesAutoresizingMaskIntoConstraints = NO; - _numberBadgeViewImpl = [[NumberBadgeView alloc] init]; - _numberBadgeViewImpl.translatesAutoresizingMaskIntoConstraints = NO; + _numberBadgeView = [[NumberBadgeView alloc] init]; + _numberBadgeView.translatesAutoresizingMaskIntoConstraints = NO; _textBadgeView = [[TextBadgeView alloc] initWithText:nil]; _textBadgeView.translatesAutoresizingMaskIntoConstraints = NO; @@ -140,7 +140,7 @@ [self.contentView addSubview:_titleLabel]; [self.contentView addSubview:_imageView]; - [self.contentView addSubview:_numberBadgeViewImpl]; + [self.contentView addSubview:_numberBadgeView]; [self.contentView addSubview:_textBadgeView]; [NSLayoutConstraint activateConstraints:@[ @@ -151,7 +151,7 @@ [_imageView.centerYAnchor constraintEqualToAnchor:_titleLabel.firstBaselineAnchor constant:-[self titleFont].capHeight / 2.0], - [_numberBadgeViewImpl.centerYAnchor + [_numberBadgeView.centerYAnchor constraintEqualToAnchor:_imageView.centerYAnchor], [_textBadgeView.centerYAnchor constraintEqualToAnchor:_imageView.centerYAnchor], @@ -167,7 +167,7 @@ @{ @"image" : _imageView, @"label" : _titleLabel, - @"numberBadge" : _numberBadgeViewImpl, + @"numberBadge" : _numberBadgeView, @"textBadge" : _textBadgeView }, @{ @@ -195,31 +195,27 @@ return self; } -- (UIView*)numberBadgeView { - return _numberBadgeViewImpl; -} - - (void)setBadgeNumber:(NSInteger)badgeNumber { - BOOL wasHidden = self.numberBadgeViewImpl.hidden; - [self.numberBadgeViewImpl setNumber:badgeNumber animated:NO]; + BOOL wasHidden = self.numberBadgeView.hidden; + [self.numberBadgeView setNumber:badgeNumber animated:NO]; // If the number badge is shown, then the text badge must be hidden. - if (!self.numberBadgeViewImpl.hidden && !self.textBadgeView.hidden) { + if (!self.numberBadgeView.hidden && !self.textBadgeView.hidden) { [self setBadgeText:nil]; } - if (!self.numberBadgeViewImpl.hidden && wasHidden) { + if (!self.numberBadgeView.hidden && wasHidden) { self.titleToBadgeConstraint.active = NO; - self.titleToBadgeConstraint = [self.numberBadgeViewImpl.leadingAnchor + self.titleToBadgeConstraint = [self.numberBadgeView.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.trailingAnchor constant:kInnerMargin]; self.titleToBadgeConstraint.active = YES; - } else if (self.numberBadgeViewImpl.hidden && !wasHidden) { + } else if (self.numberBadgeView.hidden && !wasHidden) { self.titleToBadgeConstraint.active = NO; } } - (void)setBadgeText:(NSString*)badgeText { // Only 1 badge can be visible at a time, and the number badge takes priority. - if (badgeText && !self.numberBadgeViewImpl.isHidden) { + if (badgeText && !self.numberBadgeView.isHidden) { return; } @@ -274,9 +270,7 @@ CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds); CGFloat trailingMargin = kMargin; - if (!self.numberBadgeViewImpl.hidden) { - trailingMargin += self.numberBadgeViewImpl.bounds.size.width + kInnerMargin; - } else if (!self.textBadgeView.hidden) { + if (!self.textBadgeView.hidden) { trailingMargin += self.textBadgeView.bounds.size.width + kInnerMargin; } CGFloat leadingMargin = kMargin + kImageLength + kInnerMargin;
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm index fce5e0c..bc6009cea 100644 --- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
@@ -9,6 +9,7 @@ #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/common/bookmark_pref_names.h" #include "components/feature_engagement/public/feature_constants.h" @@ -56,12 +57,15 @@ #import "ios/public/provider/chrome/browser/follow/follow_provider.h" #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h" #include "ios/web/common/user_agent.h" +#include "ios/web/public/js_messaging/web_frame.h" +#include "ios/web/public/js_messaging/web_frame_util.h" #import "ios/web/public/navigation/navigation_item.h" #import "ios/web/public/navigation/navigation_manager.h" #include "ios/web/public/web_client.h" #import "ios/web/public/web_state.h" #import "ios/web/public/web_state_observer_bridge.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/l10n_util_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -597,6 +601,11 @@ .GetFollowProvider() ->GetFollowStatus(siteInfo); if (!siteFollowed) { + std::string domainName = + web::GetMainFrame(self.webState)->GetSecurityOrigin().host(); + domainName = domainName.substr(4, domainName.length()); + strongSelf.followAction.name = l10n_util::GetNSStringF( + IDS_IOS_TOOLS_MENU_FOLLOW, base::UTF8ToUTF16(domainName)); strongSelf.pageActionsGroup.actions = [@[ strongSelf.followAction ] arrayByAddingObjectsFromArray:strongSelf.pageActionsGroup
diff --git a/ios/chrome/browser/ui/popup_menu/public/BUILD.gn b/ios/chrome/browser/ui/popup_menu/public/BUILD.gn index 292a43f..fcfa675 100644 --- a/ios/chrome/browser/ui/popup_menu/public/BUILD.gn +++ b/ios/chrome/browser/ui/popup_menu/public/BUILD.gn
@@ -36,7 +36,6 @@ "//ios/chrome/browser/ui/popup_menu/public/", "//ios/chrome/browser/ui/popup_menu/public/cells", "//ios/chrome/browser/ui/presenters", - "//ios/chrome/browser/ui/reading_list:features", "//ios/chrome/browser/ui/reading_list:reading_list_constants", "//ios/chrome/browser/ui/resources:menu_shadow", "//ios/chrome/browser/ui/table_view",
diff --git a/ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller.mm b/ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller.mm index 79aa6b3..c467a77 100644 --- a/ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller.mm +++ b/ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller.mm
@@ -5,16 +5,12 @@ #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller.h" #include "base/ios/ios_util.h" -#include "base/mac/foundation_util.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#import "ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h" #import "ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_footer_item.h" #import "ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_item.h" #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller_delegate.h" #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_ui_constants.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_constants.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" @@ -203,51 +199,6 @@ #pragma mark - UITableViewDelegate - (void)tableView:(UITableView*)tableView - willDisplayCell:(UITableViewCell*)cell - forRowAtIndexPath:(NSIndexPath*)indexPath { - TableViewItem<PopupMenuItem>* item = - [self.tableViewModel itemAtIndexPath:indexPath]; - PopupMenuToolsItem* popupToolsItem = - base::mac::ObjCCast<PopupMenuToolsItem>(item); - // Only consider doing animation if the Reading List badge is visible. - if (item.actionIdentifier != PopupMenuActionReadingList || - popupToolsItem.badgeNumber == 0) { - return; - } - // Show display animation of Reading List Unread Badge if the Reading List - // Messages experiment is enabled and a page was added by the Messages - // recently. - BOOL shouldShowUnreadBadgeAnimation = - IsReadingListMessagesEnabled() && - [[NSUserDefaults standardUserDefaults] - boolForKey:kShouldAnimateReadingListOverflowMenuUnreadCountBadge]; - if (shouldShowUnreadBadgeAnimation) { - PopupMenuToolsCell* readingListCell = - base::mac::ObjCCast<PopupMenuToolsCell>(cell); - readingListCell.numberBadgeView.alpha = 0; - readingListCell.numberBadgeView.transform = - CGAffineTransformMakeScale(0.1, 0.1); - __weak PopupMenuToolsCell* weakCell = readingListCell; - [UIView animateWithDuration:kReadingListUnreadCountBadgeAnimationDuration - delay:0.1 - options:UIViewAnimationOptionBeginFromCurrentState - animations:^{ - if (weakCell) { - weakCell.numberBadgeView.transform = CGAffineTransformIdentity; - weakCell.numberBadgeView.alpha = 1; - } - } - completion:^(BOOL finished) { - if (finished) { - [[NSUserDefaults standardUserDefaults] - setBool:NO - forKey:kShouldAnimateReadingListOverflowMenuUnreadCountBadge]; - } - }]; - } -} - -- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { UIView* cell = [self.tableView cellForRowAtIndexPath:indexPath]; CGPoint center = [cell convertPoint:cell.center toView:nil];
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn index 9f76597..0e57ac93 100644 --- a/ios/chrome/browser/ui/reading_list/BUILD.gn +++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -2,8 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//ios/web/js_compile.gni") - source_set("reading_list") { sources = [ "reading_list_coordinator.h", @@ -53,7 +51,6 @@ "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent", "//ios/chrome/browser/ui/main:scene_state_header", "//ios/chrome/browser/ui/menu", - "//ios/chrome/browser/ui/reading_list:features", "//ios/chrome/browser/ui/reading_list/resources:distillation_fail_new", "//ios/chrome/browser/ui/sharing", "//ios/chrome/browser/ui/side_swipe", @@ -79,42 +76,6 @@ configs += [ "//build/config/compiler:enable_arc" ] } -source_set("reading_list_javascript_feature") { - sources = [ - "reading_list_javascript_feature.h", - "reading_list_javascript_feature.mm", - ] - deps = [ - ":distiller_js", - ":features", - "//base", - "//components/dom_distiller/core", - "//components/infobars/core", - "//components/prefs", - "//components/reading_list/core", - "//components/ukm/ios:ukm_url_recorder", - "//ios/chrome/browser", - "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/infobars", - "//ios/chrome/browser/reading_list", - "//ios/chrome/browser/ui/reading_list:infobar", - "//ios/chrome/browser/ui/reading_list:reading_list_constants", - "//ios/web/public", - "//ios/web/public/js_messaging:js_messaging", - "//services/metrics/public/cpp:ukm_builders", - ] - configs += [ "//build/config/compiler:enable_arc" ] -} - -source_set("features") { - sources = [ - "reading_list_features.h", - "reading_list_features.mm", - ] - deps = [ "//base" ] - configs += [ "//build/config/compiler:enable_arc" ] -} - source_set("infobar") { sources = [ "ios_add_to_reading_list_infobar_delegate.h", @@ -141,13 +102,6 @@ configs += [ "//build/config/compiler:enable_arc" ] } -js_compile_bundle("distiller_js") { - visibility = [ ":reading_list_javascript_feature" ] - - closure_entry_point = "__crWeb.readingListDOM" - sources = [ "resources/dom_distiller.js" ] -} - source_set("reading_list_ui") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ @@ -171,7 +125,6 @@ "text_badge_view.mm", ] deps = [ - ":features", ":reading_list_constants", "resources:reading_list_empty", "resources:reading_list_empty_state", @@ -253,7 +206,6 @@ sources = [ "reading_list_egtest.mm" ] deps = [ ":eg_test_support+eg2", - ":features", ":reading_list_constants", "//base", "//base/test:test_support",
diff --git a/ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.mm b/ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.mm index a9a9b1f..9afffa6c 100644 --- a/ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.mm +++ b/ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.mm
@@ -115,9 +115,4 @@ return true; } -void IOSAddToReadingListInfobarDelegate::NeverShow() { - ChromeBrowserState* browser_state = - ChromeBrowserState::FromBrowserState(web_state_->GetBrowserState()); - PrefService* user_prefs = browser_state->GetPrefs(); - user_prefs->SetBoolean(kPrefReadingListMessagesNeverShow, true); -} +void IOSAddToReadingListInfobarDelegate::NeverShow() {}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_constants.h b/ios/chrome/browser/ui/reading_list/reading_list_constants.h index 3fb6c9b..c12a9b68 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_constants.h +++ b/ios/chrome/browser/ui/reading_list/reading_list_constants.h
@@ -18,13 +18,6 @@ extern NSString* const kReadingListToolbarMarkButtonID; // NSUserDefault key to save last time a Messages prompt was shown. -extern NSString* const kLastTimeUserShownReadingListMessages; extern NSString* const kLastReadingListEntryAddedFromMessages; -extern NSString* const kShouldAnimateReadingListNTPUnreadCountBadge; -extern NSString* const kShouldAnimateReadingListOverflowMenuUnreadCountBadge; -extern CGFloat const kReadingListUnreadCountBadgeAnimationDuration; - -// ChromeBrowserState pref key to never show the Reading List Message prompt. -extern const char kPrefReadingListMessagesNeverShow[]; #endif // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_constants.mm b/ios/chrome/browser/ui/reading_list/reading_list_constants.mm index 1c45e73..10997f3 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_constants.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_constants.mm
@@ -21,15 +21,5 @@ NSString* const kReadingListToolbarMarkButtonID = @"ReadingListToolbarMarkButton"; -NSString* const kLastTimeUserShownReadingListMessages = - @"LastTimeUserShownReadingListMessages"; NSString* const kLastReadingListEntryAddedFromMessages = @"LastReadingListEntryAddedFromMessages"; -NSString* const kShouldAnimateReadingListNTPUnreadCountBadge = - @"ShouldAnimateReadingListNTPUnreadCountBadge"; -NSString* const kShouldAnimateReadingListOverflowMenuUnreadCountBadge = - @"ShouldAnimateReadingListOverflowMenuUnreadCountBadge"; -CGFloat const kReadingListUnreadCountBadgeAnimationDuration = 0.3; - -const char kPrefReadingListMessagesNeverShow[] = - "reading_list_message_never_show";
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm index 35bd52a..59fd328 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -20,7 +20,6 @@ #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h" #import "ios/chrome/browser/ui/reading_list/reading_list_app_interface.h" #import "ios/chrome/browser/ui/reading_list/reading_list_constants.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #import "ios/chrome/browser/ui/table_view/table_view_constants.h" #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h" #include "ios/chrome/grit/ios_strings.h" @@ -1160,41 +1159,6 @@ assertWithMatcher:grey_nil()]; } -// Tests the long pressing the setting switch does not trigger any context menu. -- (void)testContextMenuSwitch { - AppLaunchConfiguration config = [self appConfigurationForTestCase]; - config.relaunch_policy = ForceRelaunchByCleanShutdown; - config.features_enabled.push_back(kReadingListMessages); - [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; - AddEntriesAndOpenReadingList(); - ScrollToTop(); - id<GREYMatcher> matcher = grey_allOf( - chrome_test_util::StaticTextWithAccessibilityLabel( - l10n_util::GetNSString(IDS_IOS_READING_LIST_MESSAGES_SETTING_TITLE)), - grey_ancestor(grey_kindOfClassName(@"TableViewSwitchCell")), - grey_sufficientlyVisible(), nil); - [[[EarlGrey selectElementWithMatcher:matcher] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 100) - onElementWithMatcher:grey_accessibilityID(kReadingListViewID)] - performAction:grey_longPressWithDuration(kLongPressDuration)]; - - GREYAssertFalse( - base::test::ios::WaitUntilConditionOrTimeout( - kWaitForUIElementTimeout, - ^BOOL { - NSError* error = nil; - // Check for _UIContextMenuView so it would catch both native - // and custom context menu. - [[EarlGrey - selectElementWithMatcher:grey_kindOfClassName( - @"_UIContextMenuContainerView")] - assertWithMatcher:grey_sufficientlyVisible() - error:&error]; - return error == nil; - }), - @"Context menu is displayed on settings button."); -} - // Tests the Copy Link context menu action for a reading list entry. - (void)testContextMenuCopyLink { AddEntriesAndOpenReadingList();
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_features.h b/ios/chrome/browser/ui/reading_list/reading_list_features.h deleted file mode 100644 index 0fd17940..0000000 --- a/ios/chrome/browser/ui/reading_list/reading_list_features.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2021 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_BROWSER_UI_READING_LIST_READING_LIST_FEATURES_H_ -#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_FEATURES_H_ - -#include "base/feature_list.h" - -// The feature to enable or disable the Reading List Messages. -extern const base::Feature kReadingListMessages; - -// The feature to enable or disable Reading List Time To Read. -extern const base::Feature kReadingListTimeToRead; - -// Whether the Reading List Messages feature is turned on, including the -// JavaScript exeuction and Messages presentation. -bool IsReadingListMessagesEnabled(); - -// Whether the Reading List Time to Read feature is turned on. -bool IsReadingListTimeToReadEnabled(); - -// Whether only the JavaScript should be executed (e.g. do not show the Message -// even if the heuristics are met). -bool ShouldNotPresentReadingListMessage(); - -#endif // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_FEATURES_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_features.mm b/ios/chrome/browser/ui/reading_list/reading_list_features.mm deleted file mode 100644 index 8f43494a..0000000 --- a/ios/chrome/browser/ui/reading_list/reading_list_features.mm +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/ui/reading_list/reading_list_features.h" - -#include "base/metrics/field_trial_params.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -const char kReadingListMessagesOnlyJavaScriptExecutionParam[] = - "javascript_only"; - -const base::Feature kReadingListMessages{"ReadingListMessages", - base::FEATURE_DISABLED_BY_DEFAULT}; - -const base::Feature kReadingListTimeToRead{"ReadingListTimeToRead", - base::FEATURE_DISABLED_BY_DEFAULT}; - -bool IsReadingListMessagesEnabled() { - return base::FeatureList::IsEnabled(kReadingListMessages); -} - -bool IsReadingListTimeToReadEnabled() { - return base::FeatureList::IsEnabled(kReadingListTimeToRead); -} - -bool ShouldNotPresentReadingListMessage() { - return base::GetFieldTrialParamByFeatureAsBool( - kReadingListMessages, - kReadingListMessagesOnlyJavaScriptExecutionParam, false) || - IsReadingListTimeToReadEnabled(); -}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.h b/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.h deleted file mode 100644 index 86d63683..0000000 --- a/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2021 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_BROWSER_UI_READING_LIST_READING_LIST_JAVASCRIPT_FEATURE_H_ -#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_JAVASCRIPT_FEATURE_H_ - -#include "base/no_destructor.h" -#import "ios/web/public/js_messaging/java_script_feature.h" - -// A feature which receives DOM attributes and uses them to determine Time to -// Read and Distillibility. -class ReadingListJavaScriptFeature : public web::JavaScriptFeature { - private: - friend class base::NoDestructor<ReadingListJavaScriptFeature>; - - ReadingListJavaScriptFeature(); - ~ReadingListJavaScriptFeature() override; - - ReadingListJavaScriptFeature(const ReadingListJavaScriptFeature&) = delete; - ReadingListJavaScriptFeature& operator=(const ReadingListJavaScriptFeature&) = - delete; - - // JavaScriptFeature: - absl::optional<std::string> GetScriptMessageHandlerName() const override; - void ScriptMessageReceived(web::WebState* web_state, - const web::ScriptMessage& message) override; - - // Returns true if there has not been a presented Add to Reading List Messages - // prompt in this browsing session. - bool CanShowReadingListMessages(); - // Saves that an Add to Reading List Messages prompt has been presented. - void SaveReadingListMessagesShownTime(); -}; - -#endif // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_JAVASCRIPT_FEATURE_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm b/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm deleted file mode 100644 index 7b30d71..0000000 --- a/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm +++ /dev/null
@@ -1,241 +0,0 @@ -// Copyright 2021 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 "ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.h" - -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" -#include "base/time/time.h" -#include "base/values.h" -#include "components/dom_distiller/core/distillable_page_detector.h" -#include "components/dom_distiller/core/page_features.h" -#include "components/infobars/core/infobar_manager.h" -#include "components/prefs/pref_service.h" -#include "components/reading_list/core/reading_list_model.h" -#include "components/ukm/ios/ukm_url_recorder.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/chrome_url_util.h" -#include "ios/chrome/browser/infobars/infobar_ios.h" -#include "ios/chrome/browser/infobars/infobar_manager_impl.h" -#include "ios/chrome/browser/reading_list/reading_list_model_factory.h" -#import "ios/chrome/browser/ui/reading_list/ios_add_to_reading_list_infobar_delegate.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_constants.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" -#import "ios/web/public/js_messaging/java_script_feature_util.h" -#import "ios/web/public/js_messaging/script_message.h" -#import "ios/web/public/web_state.h" -#include "services/metrics/public/cpp/ukm_builders.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -const char kScriptName[] = "distiller_js"; -const char kScriptHandlerName[] = "ReadingListDOMMessageHandler"; -// Heuristic for words per minute reading speed. -const int kWordCountPerMinute = 275; -// Minimum read time to show the Messages prompt. -const double kReadTimeThreshold = 7.0; -} // namespace - -ReadingListJavaScriptFeature::ReadingListJavaScriptFeature() - : JavaScriptFeature( - ContentWorld::kAnyContentWorld, - {FeatureScript::CreateWithFilename( - kScriptName, - FeatureScript::InjectionTime::kDocumentEnd, - FeatureScript::TargetFrames::kMainFrame, - FeatureScript::ReinjectionBehavior::kInjectOncePerWindow)}, - {web::java_script_features::GetCommonJavaScriptFeature()}) {} - -ReadingListJavaScriptFeature::~ReadingListJavaScriptFeature() = default; - -absl::optional<std::string> -ReadingListJavaScriptFeature::GetScriptMessageHandlerName() const { - return kScriptHandlerName; -} - -void ReadingListJavaScriptFeature::ScriptMessageReceived( - web::WebState* web_state, - const web::ScriptMessage& message) { - if (!message.body() || !message.body()->is_dict()) { - // Ignore malformed responses. - return; - } - // The JavaScript shouldn't be executed in incognito pages. - DCHECK(!web_state->GetBrowserState()->IsOffTheRecord()); - - absl::optional<GURL> url = message.request_url(); - if (!url.has_value() || UrlHasChromeScheme(url.value()) || - url.value().SchemeIs(url::kAboutScheme)) { - // Ignore any Chrome-handled or NTP pages. - return; - } - - absl::optional<double> opt_num_elements = - message.body()->FindDoubleKey("numElements"); - double num_elements = 0.0; - if (opt_num_elements.has_value()) { - num_elements = opt_num_elements.value(); - } - - absl::optional<double> opt_num_anchors = - message.body()->FindDoubleKey("numAnchors"); - double num_anchors = 0.0; - if (opt_num_anchors.has_value()) { - num_anchors = opt_num_anchors.value(); - } - - absl::optional<double> opt_num_forms = - message.body()->FindDoubleKey("numForms"); - double num_forms = 0.0; - if (opt_num_forms.has_value()) { - num_forms = opt_num_forms.value(); - } - - absl::optional<double> opt_moz_score = - message.body()->FindDoubleKey("mozScore"); - double moz_score = 0.0; - if (opt_moz_score.has_value()) { - moz_score = opt_moz_score.value(); - } - - absl::optional<double> opt_moz_sqrt = - message.body()->FindDoubleKey("mozScoreAllSqrt"); - double moz_sqrt = 0.0; - if (opt_moz_sqrt.has_value()) { - moz_sqrt = opt_moz_sqrt.value(); - } - - absl::optional<double> opt_moz_linear = - message.body()->FindDoubleKey("mozScoreAllLinear"); - double moz_linear = 0.0; - if (opt_moz_linear.has_value()) { - moz_linear = opt_moz_linear.value(); - } - - absl::optional<double> time = message.body()->FindDoubleKey("time"); - if (time.has_value()) { - UMA_HISTOGRAM_TIMES("IOS.ReadingList.Javascript.ExecutionTime", - base::Milliseconds(time.value())); - } - - std::vector<double> result = dom_distiller::CalculateDerivedFeatures( - true, message.request_url().value(), num_elements, num_anchors, num_forms, - moz_score, moz_sqrt, moz_linear); - - const dom_distiller::DistillablePageDetector* detector = - dom_distiller::DistillablePageDetector::GetNewModel(); - // Equivalent of DistillablePageDetector::Classify(). - double score = detector->Score(result) - detector->GetThreshold(); - // Translate score by +1 to make histogram logging simpler by keeping all - // scores positive. Multiply by 100 to get granular scoring logging to the - // hundredths digit. - base::UmaHistogramCustomCounts( - "IOS.ReadingList.Javascript.RegularDistillabilityScore", - (score + 1) * 100, 0, 400, 50); - - const dom_distiller::DistillablePageDetector* long_detector = - dom_distiller::DistillablePageDetector::GetLongPageModel(); - // Equivalent of DistillablePageDetector::Classify(). - double long_score = - long_detector->Score(result) - long_detector->GetThreshold(); - // Translate score by +1 to make histogram logging simpler by keeping all - // scores positive. Multiply by 100 to get granular scoring logging to the - // hundredths digit. - base::UmaHistogramCustomCounts( - "IOS.ReadingList.Javascript.LongPageDistillabilityScore", - (long_score + 1) * 100, 0, 400, 50); - - // Calculate Time to Read - absl::optional<double> opt_word_count = - message.body()->FindDoubleKey("wordCount"); - double estimated_read_time = 0.0; - if (opt_word_count.has_value()) { - estimated_read_time = opt_word_count.value() / kWordCountPerMinute; - base::UmaHistogramCounts100("IOS.ReadingList.Javascript.TimeToRead", - estimated_read_time); - } - - ReadingListModel* model = ReadingListModelFactory::GetForBrowserState( - ChromeBrowserState::FromBrowserState(web_state->GetBrowserState())); - if (model->loaded()) { - const ReadingListEntry* entry = model->GetEntryByURL(url.value()); - if (entry) { - // Update an existing Reading List entry with the estimated time to read. - // Either way, return early to not show a Messages banner for an existing - // Reading List entry. - if (entry->EstimatedReadTime().is_zero()) { - model->SetEstimatedReadTime(url.value(), - base::Minutes(estimated_read_time)); - } - return; - } - } - if (ShouldNotPresentReadingListMessage()) { - // Log the UKM and return early if the feature should only be executing - // JavaScript at this time. - ukm::SourceId sourceID = ukm::GetSourceIdForWebStateDocument(web_state); - if (sourceID != ukm::kInvalidSourceId) { - // Round to the nearest tenth, and additionally round to a .5 level of - // granularity if <0.5 or > 1.5. Get accuracy to the tenth digit in UKM by - // multiplying by 10. - int score_minimization = (int)(round(score * 10)); - int long_score_minimization = (int)(round(long_score * 10)); - if (score_minimization > 15 || score_minimization < 5) { - score_minimization = ((score_minimization + 2.5) / 5) * 5; - } - if (long_score_minimization > 15 || long_score_minimization < 5) { - long_score_minimization = ((long_score_minimization + 2.5) / 5) * 5; - } - ukm::builders::IOS_PageReadability(sourceID) - .SetDistilibilityScore(score_minimization) - .SetDistilibilityLongScore(long_score_minimization) - .Record(ukm::UkmRecorder::Get()); - } - return; - } - if (!web_state->IsVisible()) { - // Do not show the Messages banner if the WebState is not visible, but delay - // this check in case the estimated read time can be set for an existing - // entry. - return; - } - ChromeBrowserState* browser_state = - ChromeBrowserState::FromBrowserState(web_state->GetBrowserState()); - PrefService* user_prefs = browser_state->GetPrefs(); - bool neverShowPrefSet = - user_prefs->GetBoolean(kPrefReadingListMessagesNeverShow); - if (neverShowPrefSet) { - // Do not show prompt if user explicitly selected to never show it. - return; - } - - infobars::InfoBarManager* manager = - InfoBarManagerImpl::FromWebState(web_state); - if (manager && score > 0 && estimated_read_time > kReadTimeThreshold && - CanShowReadingListMessages()) { - SaveReadingListMessagesShownTime(); - auto delegate = std::make_unique<IOSAddToReadingListInfobarDelegate>( - web_state->GetVisibleURL(), web_state->GetTitle(), - static_cast<int>(estimated_read_time), score, long_score, model, - web_state); - std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>( - InfobarType::kInfobarTypeAddToReadingList, std::move(delegate), false); - manager->AddInfoBar(std::move(infobar), true); - } -} - -bool ReadingListJavaScriptFeature::CanShowReadingListMessages() { - NSDate* last_shown_timestamp = [[NSUserDefaults standardUserDefaults] - objectForKey:kLastTimeUserShownReadingListMessages]; - return !last_shown_timestamp; -} - -void ReadingListJavaScriptFeature::SaveReadingListMessagesShownTime() { - [[NSUserDefaults standardUserDefaults] - setObject:[NSDate date] - forKey:kLastTimeUserShownReadingListMessages]; -}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm index 3b8f2b23..81f67cd 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.mm
@@ -8,7 +8,6 @@ #include "base/strings/sys_string_conversions.h" #include "components/reading_list/core/reading_list_entry.h" #include "components/url_formatter/url_formatter.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_util.h" #import "ios/chrome/browser/ui/reading_list/reading_list_table_view_item.h" @@ -83,13 +82,6 @@ hasDistillationDetails ? entry->DistillationSize() : 0; item.distillationSizeText = GetReadingListCellDistillationSizeText(distillationSize); - if (IsReadingListTimeToReadEnabled() && - !entry->EstimatedReadTime().is_zero()) { - item.estimatedReadTimeText = - base::SysUTF16ToNSString(ui::TimeFormat::Simple( - ui::TimeFormat::FORMAT_DURATION, ui::TimeFormat::LENGTH_SHORT, - entry->EstimatedReadTime())); - } item.customActionFactory = self.customActionFactory; return item; }
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm index ec14d508..891ce10e 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -10,9 +10,6 @@ #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#import "components/prefs/ios/pref_observer_bridge.h" -#include "components/prefs/pref_change_registrar.h" -#include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #import "ios/chrome/app/tests_hook.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -25,7 +22,6 @@ #import "ios/chrome/browser/ui/reading_list/reading_list_constants.h" #import "ios/chrome/browser/ui/reading_list/reading_list_data_sink.h" #import "ios/chrome/browser/ui/reading_list/reading_list_data_source.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_item.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_updater.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_view_controller_audience.h" @@ -57,17 +53,10 @@ }; // Identifiers for sections in the reading list. typedef NS_ENUM(NSInteger, SectionIdentifier) { - SectionIdentifierMessagesSwitch = kSectionIdentifierEnumZero, - SectionIdentifierUnread, + SectionIdentifierUnread = kSectionIdentifierEnumZero, SectionIdentifierRead, }; -// User action names for toggling whether to show the Reading List Message. -const char kReadingListMessagesToggleUserActionTurnOn[] = - "IOS.ReadingList.MessagesPromptToggle.On"; -const char kReadingListMessagesToggleUserActionTurnOff[] = - "IOS.ReadingList.MessagesPromptToggle.Off"; - // Returns the ReadingListSelectionState corresponding with the provided numbers // of read and unread items. ReadingListSelectionState GetSelectionStateForSelectedCounts( @@ -83,15 +72,9 @@ } } // namespace -@interface ReadingListTableViewController () <PrefObserverDelegate, - ReadingListDataSink, +@interface ReadingListTableViewController () <ReadingListDataSink, ReadingListToolbarButtonCommands, - TableViewURLDragDataSource> { - // Pref observer to track changes to prefs. - std::unique_ptr<PrefObserverBridge> _prefObserverBridge; - // Registrar for pref changes notifications. - std::unique_ptr<PrefChangeRegistrar> _prefChangeRegistrar; -} + TableViewURLDragDataSource> // Redefine the model to return ReadingListListItems @property(nonatomic, readonly) @@ -119,8 +102,6 @@ @property(nonatomic, readonly, getter=isEditingWithSwipe) BOOL editingWithSwipe; // Handler for URL drag interactions. @property(nonatomic, strong) TableViewURLDragDropHandler* dragDropHandler; -// The toggle setting of showing the Reading List Messages prompt. -@property(nonatomic, strong) SyncSwitchItem* messagesPromptToggleSwitchItem; @end @implementation ReadingListTableViewController @@ -222,22 +203,6 @@ - (void)viewDidLoad { [super viewDidLoad]; - if (IsReadingListMessagesEnabled()) { - // Reset the boolean if an entry was added from a Messages prompt since the - // user has now seen that new entry in the Reading List. - [[NSUserDefaults standardUserDefaults] - setBool:NO - forKey:kLastReadingListEntryAddedFromMessages]; - - // pref observer listens to the Messages prompt in case two Reading Lists - // are shown in multiwindow. - _prefChangeRegistrar = std::make_unique<PrefChangeRegistrar>(); - _prefChangeRegistrar->Init(self.browser->GetBrowserState()->GetPrefs()); - _prefObserverBridge.reset(new PrefObserverBridge(self)); - _prefObserverBridge->ObserveChangesForPreference( - kPrefReadingListMessagesNeverShow, _prefChangeRegistrar.get()); - } - self.title = l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_READING_LIST); self.tableView.accessibilityIdentifier = @@ -272,34 +237,6 @@ #pragma mark - UITableViewDataSource -- (UITableViewCell*)tableView:(UITableView*)tableView - cellForRowAtIndexPath:(NSIndexPath*)indexPath { - UITableViewCell* cell = [super tableView:tableView - cellForRowAtIndexPath:indexPath]; - if ([cell isKindOfClass:[TableViewSwitchCell class]]) { - DCHECK(IsReadingListMessagesEnabled()); - TableViewSwitchCell* switchCell = - base::mac::ObjCCastStrict<TableViewSwitchCell>(cell); - [switchCell.switchView addTarget:self - action:@selector(switchAction:) - forControlEvents:UIControlEventValueChanged]; - } - return cell; -} - -- (UIView*)tableView:(UITableView*)tableView - viewForFooterInSection:(NSInteger)section { - UIView* footer = [super tableView:tableView viewForFooterInSection:section]; - if ([footer isKindOfClass:[TableViewTextHeaderFooterView class]]) { - DCHECK(IsReadingListMessagesEnabled()); - TableViewTextHeaderFooterView* textFooter = - base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(footer); - textFooter.subtitleLabel.numberOfLines = 0; - textFooter.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping; - } - return footer; -} - - (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath { @@ -311,47 +248,10 @@ removeEmptySections:NO]; } -#pragma mark - TableViewSwitchCell action - -- (void)switchAction:(UISwitch*)sender { - PrefService* user_prefs = self.browser->GetBrowserState()->GetPrefs(); - BOOL neverShowPrompt = ![sender isOn]; - if (neverShowPrompt) { - base::RecordAction( - base::UserMetricsAction(kReadingListMessagesToggleUserActionTurnOff)); - } else { - base::RecordAction( - base::UserMetricsAction(kReadingListMessagesToggleUserActionTurnOn)); - } - user_prefs->SetBoolean(kPrefReadingListMessagesNeverShow, neverShowPrompt); -} - -#pragma mark - PrefObserverDelegate - -- (void)onPreferenceChanged:(const std::string&)preferenceName { - DCHECK(IsReadingListMessagesEnabled()); - if (preferenceName == kPrefReadingListMessagesNeverShow) { - PrefService* user_prefs = self.browser->GetBrowserState()->GetPrefs(); - self.messagesPromptToggleSwitchItem.on = - !user_prefs->GetBoolean(kPrefReadingListMessagesNeverShow); - NSIndexPath* indexPath = [self.tableViewModel - indexPathForItemType:SwitchItemType - sectionIdentifier:SectionIdentifierMessagesSwitch]; - [self reconfigureCellsForItems:@[ [self.tableViewModel - itemAtIndexPath:indexPath] ]]; - } -} - #pragma mark - UITableViewDelegate - (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { - UITableViewCell* cell = [self tableView:tableView - cellForRowAtIndexPath:indexPath]; - if ([cell isKindOfClass:[TableViewSwitchCell class]]) { - DCHECK(IsReadingListMessagesEnabled()); - return; - } if (self.editing) { // Update the selected item counts and the toolbar buttons. NSInteger sectionID = [self.tableViewModel @@ -434,11 +334,6 @@ - (void)loadModel { [super loadModel]; self.dataSourceModifiedWhileEditing = NO; - // Add Reading List Messages toggle here so that it shows even if there are no - // entries. - if (IsReadingListMessagesEnabled()) { - [self addPromptToggleItemAndSection]; - } if (self.dataSource.hasElements) { [self loadItems]; [self.audience readingListHasItems:YES]; @@ -724,29 +619,6 @@ [self updateToolbarItems]; } -// Adds section and SyncSwitchItem instance for the toggle setting of showing -// the Reading List Messages prompt. -- (void)addPromptToggleItemAndSection { - TableViewModel* model = self.tableViewModel; - [model addSectionWithIdentifier:SectionIdentifierMessagesSwitch]; - self.messagesPromptToggleSwitchItem = - [[SyncSwitchItem alloc] initWithType:SwitchItemType]; - self.messagesPromptToggleSwitchItem.text = - l10n_util::GetNSString(IDS_IOS_READING_LIST_MESSAGES_SETTING_TITLE); - self.messagesPromptToggleSwitchItem.enabled = YES; - PrefService* user_prefs = self.browser->GetBrowserState()->GetPrefs(); - self.messagesPromptToggleSwitchItem.on = - !user_prefs->GetBoolean(kPrefReadingListMessagesNeverShow); - [model addItem:self.messagesPromptToggleSwitchItem - toSectionWithIdentifier:SectionIdentifierMessagesSwitch]; - TableViewLinkHeaderFooterItem* footerItem = - [[TableViewLinkHeaderFooterItem alloc] initWithType:SwitchItemFooterType]; - footerItem.text = - l10n_util::GetNSString(IDS_IOS_READING_LIST_MESSAGES_MODAL_DESCRIPTION); - [model setFooter:footerItem - forSectionWithIdentifier:SectionIdentifierMessagesSwitch]; -} - // Adds |items| to self.tableViewModel for the section designated by // |sectionID|. - (void)loadItemsFromArray:(NSArray<id<ReadingListListItem>>*)items @@ -779,8 +651,6 @@ case SectionIdentifierUnread: header.text = l10n_util::GetNSString(IDS_IOS_READING_LIST_UNREAD_HEADER); break; - case SectionIdentifierMessagesSwitch: - break; } return header; } @@ -947,9 +817,6 @@ BOOL hasUnreadItems = [self hasItemInSection:SectionIdentifierUnread]; BOOL creatingReadSection = (sectionID == SectionIdentifierRead); NSInteger sectionIndex = (hasUnreadItems && creatingReadSection) ? 1 : 0; - if (IsReadingListMessagesEnabled()) { - sectionIndex++; - } void (^updates)(void) = ^{ [model insertSectionWithIdentifier:sectionID atIndex:sectionIndex];
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm index 5df14bd..cc138502 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_item.mm
@@ -10,7 +10,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "components/url_formatter/elide_url.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h" #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_util.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h" @@ -89,11 +88,7 @@ TableViewURLCell* URLCell = base::mac::ObjCCastStrict<TableViewURLCell>(cell); URLCell.titleLabel.text = [self titleLabelText]; URLCell.URLLabel.text = [self URLLabelText]; - if (IsReadingListTimeToReadEnabled()) { - URLCell.metadataLabel.text = self.estimatedReadTimeText; - } else { - URLCell.metadataLabel.text = self.distillationSizeText; - } + URLCell.metadataLabel.text = self.distillationSizeText; URLCell.cellUniqueIdentifier = base::SysUTF8ToNSString(self.entryURL.host()); URLCell.accessibilityTraits |= UIAccessibilityTraitButton;
diff --git a/ios/chrome/browser/ui/reading_list/resources/dom_distiller.js b/ios/chrome/browser/ui/reading_list/resources/dom_distiller.js deleted file mode 100644 index 330c520..0000000 --- a/ios/chrome/browser/ui/reading_list/resources/dom_distiller.js +++ /dev/null
@@ -1,152 +0,0 @@ -// Copyright 2021 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. - -// The implementation here to calculate the mozScore, mozScoreAllSqrt, -// and mozScoreAllLinear is a copy of what is found in -// https://github.com/chromium/dom-distiller/blob/master/ -// heuristics/distillable/extract_features.js#L13 -// The visibility check is removed for its poor performance, and -// getElementsByTagName() is used for its faster runtime. -// In addition, the logic is restructured to only need -// to retrieve the <p> and <pre> elements once. - -goog.provide('__crWeb.readingListDOM'); - -(function() { -/** - * Determines if the page has a particular tag indicating article content. - * @return {boolean} - */ -function _hasOGArticle() { - const elems = document.head.querySelectorAll( - 'meta[property="og:type"],meta[name="og:type"]'); - for (const elem of elems) { - if (elem.content && elem.content.toUpperCase() === 'ARTICLE') { - return true; - } - } - return false; -} - -/** - * Helper method for _baselineMozScore() to calculate the character length in an - * element. - * @param {Element} element An element to calculate the contained text length. - * @return {float} The character length of text in |element|. - */ -function _getTextLengthForNode(element) { - let unlikelyCandidates = new RegExp( - 'banner|combx|comment|community|disqus|extra|foot|header|menu|related|' + - 'remark|rss|share|shoutbox|sidebar|skyscraper|sponsor|ad-break|agegate|' + - 'pagination|pager|popup'); - let possibleCandiates = new RegExp('and|article|body|column|main|shadow'); - let matchString = element.className + ' ' + element.id; - if (unlikelyCandidates.test(matchString) && - !possibleCandiates.test(matchString)) { - return 0; - } - - if (element.matches && element.matches('li p')) { - return 0; - } - - var textContentLength = element.textContent.length; - // Caps the max character length to 1000 for each element. - return Math.min(1000, textContentLength); -} - -/** - * Returns a list of element text lengths for the elements passed in. - * @param {!HTMLCollection} pElements List of all <p> elements. - * @param {!HTMLCollection} preElements List of all <pre> elements. - * element. - * @return {Array} - */ -function _getPageTextContent(pElements, preElements) { - var text_lengths = []; - for (var i = 0; i < pElements.length; i++) { - var element = pElements[i]; - text_lengths.push(_getTextLengthForNode(element)); - } - for (var i = 0; i < preElements.length; i++) { - var element = preElements[i]; - text_lengths.push(_getTextLengthForNode(element)); - } - return text_lengths; -} - -/** - * Calculates the readability score of the page based on the element text length - * list retrieved from _getPageTextContent(). - * @param {!Array} textList List of element text lengths. - * @param {!float} power Exponent applied to scoring. - * @param {!int} cut Minimum word length in order to count the text in the - * element. - * @return {float} - */ -function _calculateMozScore(textList, power, cut) { - score = 0; - for (var i = 0; i < textList.length; i++) { - if (textList[i] < cut) { - continue; - } - score += Math.pow(textList[i] - cut, power); - } - return score; -} - -// Retrieves various DOM features and sends them back to the native code. -function _retrieveFeatures() { - // Measure execution time to ensure that it remains performant - // (i.e. single digit milliseconds). - const start = performance.now(); - - const body = document.body; - var p_elements = document.body.getElementsByTagName('p'); - var pre_elements = document.body.getElementsByTagName('pre'); - if (!body) { - return; - } - - // Calculate word count in p tags. - var wordCount = 0; - for (var i = 0; i < p_elements.length; i++) { - var matches = p_elements[i].innerText.match(/[\u00ff-\uffff]|\S+/g); - if (matches) { - wordCount += matches.length; - } - } - - var elementTextLengthList = _getPageTextContent(p_elements, pre_elements); - - const result = { - 'opengraph': _hasOGArticle(), - 'url': document.location.href, - 'numElements': body.getElementsByTagName('*').length, - 'numAnchors': body.getElementsByTagName('a').length, - 'numForms': body.getElementsByTagName('form').length, - 'wordCount': wordCount, - 'mozScore': Math.min( - 6 * Math.sqrt(1000 - 140), - _calculateMozScore(elementTextLengthList, 0.5, 140)), - 'mozScoreAllSqrt': Math.min( - 6 * Math.sqrt(1000), _calculateMozScore(elementTextLengthList, 0.5, 0)), - 'mozScoreAllLinear': - Math.min(6 * 1000, _calculateMozScore(elementTextLengthList, 1, 0)), - } - - const end = performance.now(); - const total = end - start; - result['time'] = total; - __gCrWeb.common.sendWebKitMessage('ReadingListDOMMessageHandler', result); -} - - -// Delay execution for 1 second in case content is added after the DOM is -// created. Delaying can also help prevent performance issues as the page may -// be busy right at document end time. -setTimeout(function() { - _retrieveFeatures(); -}, 1000); -}());
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn index ea5fe38..d33517ce 100644 --- a/ios/chrome/browser/web/BUILD.gn +++ b/ios/chrome/browser/web/BUILD.gn
@@ -248,8 +248,6 @@ "//ios/chrome/browser/ui/elements", "//ios/chrome/browser/ui/infobars/coordinators", "//ios/chrome/browser/ui/infobars/resources:infobar_popup_blocker", - "//ios/chrome/browser/ui/reading_list:features", - "//ios/chrome/browser/ui/reading_list:reading_list_javascript_feature", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/web:feature_flags", "//ios/chrome/browser/web/font_size",
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm index c7e4f53..b1be9452 100644 --- a/ios/chrome/browser/web/chrome_web_client.mm +++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -45,8 +45,6 @@ #import "ios/chrome/browser/search_engines/search_engine_tab_helper_factory.h" #include "ios/chrome/browser/ssl/ios_ssl_error_handler.h" #import "ios/chrome/browser/ui/elements/windowed_container_view.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_features.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.h" #include "ios/chrome/browser/ui/ui_feature_flags.h" #include "ios/chrome/browser/web/error_page_controller_bridge.h" #import "ios/chrome/browser/web/error_page_util.h" @@ -268,14 +266,6 @@ features.push_back(print_feature.get()); - BOOL shouldInjectReadingListJavaScript = - IsReadingListMessagesEnabled() || IsReadingListTimeToReadEnabled(); - if (!browser_state->IsOffTheRecord() && shouldInjectReadingListJavaScript) { - static base::NoDestructor<ReadingListJavaScriptFeature> - reading_list_feature; - features.push_back(reading_list_feature.get()); - } - features.push_back(autofill::AutofillJavaScriptFeature::GetInstance()); features.push_back(autofill::FormHandlersJavaScriptFeature::GetInstance()); features.push_back(
diff --git a/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_chromium_strings.grd b/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_chromium_strings.grd index a18593f8..8415e67e 100644 --- a/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_chromium_strings.grd +++ b/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_chromium_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_content_widget_extension_chromium_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_content_widget_extension_chromium_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_content_widget_extension_chromium_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_content_widget_extension_chromium_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_content_widget_extension_chromium_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_content_widget_extension_chromium_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_content_widget_extension_chromium_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_google_chrome_strings.grd b/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_google_chrome_strings.grd index 942f4dc..a15fcf41 100644 --- a/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_google_chrome_strings.grd +++ b/ios/chrome/content_widget_extension/strings/ios_content_widget_extension_google_chrome_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_content_widget_extension_google_chrome_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_content_widget_extension_google_chrome_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_content_widget_extension_google_chrome_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_content_widget_extension_google_chrome_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_content_widget_extension_google_chrome_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_content_widget_extension_google_chrome_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_content_widget_extension_google_chrome_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd index 02711a7..0099fe2 100644 --- a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd +++ b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_credential_provider_extension_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_credential_provider_extension_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_credential_provider_extension_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_credential_provider_extension_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_credential_provider_extension_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_credential_provider_extension_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_credential_provider_extension_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_chromium_strings.grd b/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_chromium_strings.grd index 9abc66a..839e495e 100644 --- a/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_chromium_strings.grd +++ b/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_chromium_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_search_widget_extension_chromium_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_search_widget_extension_chromium_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_search_widget_extension_chromium_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_search_widget_extension_chromium_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_search_widget_extension_chromium_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_search_widget_extension_chromium_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_search_widget_extension_chromium_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_google_chrome_strings.grd b/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_google_chrome_strings.grd index 5e2ebed..09942fd 100644 --- a/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_google_chrome_strings.grd +++ b/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_google_chrome_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_search_widget_extension_google_chrome_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_search_widget_extension_google_chrome_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_search_widget_extension_google_chrome_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_search_widget_extension_google_chrome_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_search_widget_extension_google_chrome_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_search_widget_extension_google_chrome_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_search_widget_extension_google_chrome_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_strings.grd b/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_strings.grd index 5bd7eac9..a3cd5d2 100644 --- a/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_strings.grd +++ b/ios/chrome/search_widget_extension/strings/ios_search_widget_extension_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_search_widget_extension_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_search_widget_extension_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_search_widget_extension_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_search_widget_extension_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_search_widget_extension_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_search_widget_extension_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_search_widget_extension_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/share_extension/strings/ios_share_extension_strings.grd b/ios/chrome/share_extension/strings/ios_share_extension_strings.grd index b6261fa..61cf2d1 100644 --- a/ios/chrome/share_extension/strings/ios_share_extension_strings.grd +++ b/ios/chrome/share_extension/strings/ios_share_extension_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_share_extension_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_share_extension_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_share_extension_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_share_extension_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_share_extension_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_share_extension_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_share_extension_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index f938fed..7526374 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -206,7 +206,6 @@ "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common:unit_tests", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm:unit_tests", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords:unit_tests", - "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/reading_list:unit_tests", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card:unit_tests", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate:unit_tests", "//ios/chrome/browser/itunes_urls:unit_tests",
diff --git a/ios/chrome/widget_kit_extension/strings/ios_widget_kit_extension_strings.grd b/ios/chrome/widget_kit_extension/strings/ios_widget_kit_extension_strings.grd index a808b984..278ac8d 100644 --- a/ios/chrome/widget_kit_extension/strings/ios_widget_kit_extension_strings.grd +++ b/ios/chrome/widget_kit_extension/strings/ios_widget_kit_extension_strings.grd
@@ -27,6 +27,7 @@ <output filename="ios_widget_kit_extension_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ios_widget_kit_extension_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ios_widget_kit_extension_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ios_widget_kit_extension_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ios_widget_kit_extension_strings_da.pak" type="data_package" lang="da" /> <output filename="ios_widget_kit_extension_strings_de.pak" type="data_package" lang="de" /> <output filename="ios_widget_kit_extension_strings_el.pak" type="data_package" lang="el" />
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 1890f80..7d14df0 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -42c1d86956222a7dbc36054d79b1dcfc062ab9c1 \ No newline at end of file +c845e7497c3c4b7858bdb40c6d913b547f966703 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index c61936a..dcd00e4 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -a74ef26523f4d5ad79b47b949c750a40f7d2ece9 \ No newline at end of file +c29e083107dfc413ed0fa18723f0b6d8f28b6b61 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 05f194a0..9c048c51 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e3e4587efc83cab22ee371711ca4bd6e244bcf3a \ No newline at end of file +061028041a0e316edcc94192ffb0f467797d7366 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 1e639d6..42f4b9be 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -06693307966e8d1d560fa685a17a4cb175cc0067 \ No newline at end of file +d9e0efac4acf08da8b4c9b974f2e2c4bbdbc2552 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index b9bbcf89..05d3e16 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -4ea49fb7d8d6c6dd2e74d2589d0cd134d52494f1 \ No newline at end of file +56e335418f365933b961d4cd98bc53686a136a39 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 50a1d84d..4828938c 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -d3a61aeb200cf92b3501ce2a6d2455645511489c \ No newline at end of file +d9b3ca488bd2564e0d57e2084ed7150d49880c08 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index e61646ba..f5e26f0 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e40edc33867226eb7f4fe4fca16341da9f65bdba \ No newline at end of file +68c21bcbcc5d423a8c97980a5a3692bd0c54b45b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 213330a..160c315 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -929f68afddbe50f2605c859128b01a9913ab949a \ No newline at end of file +e63cd9966c47495d07165f400cd27c593597b821 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index f26d8e32..df2bc11e 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -96bfbaf4040ff54face02d03cd0964b79ae3a5ac \ No newline at end of file +b106b323b5b636aa3d98ba17fb1cb7d3b099f4a2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 8a0d828..d4146ac5 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -92616378daea70da22a9f8ecefc11b76ffcc527f \ No newline at end of file +c8d28f670c5f9160e08327b407bc435af84e98fd \ No newline at end of file
diff --git a/media/fuchsia/cdm/client/BUILD.gn b/media/fuchsia/cdm/client/BUILD.gn index 811750f..eda464d 100644 --- a/media/fuchsia/cdm/client/BUILD.gn +++ b/media/fuchsia/cdm/client/BUILD.gn
@@ -14,7 +14,7 @@ deps = [ "//media", - "//media/fuchsia/mojom:cdm_provider", + "//media/fuchsia/mojom:fuchsia_media_resource_provider", "//third_party/blink/public:blink_headers", ] }
diff --git a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc index a0c47dd..60c713e 100644 --- a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc +++ b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc
@@ -20,11 +20,12 @@ const std::string& key_system, fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> cdm_request) { - if (!cdm_provider_) { - interface_broker_->GetInterface(cdm_provider_.BindNewPipeAndPassReceiver()); + if (!media_resource_provider_) { + interface_broker_->GetInterface( + media_resource_provider_.BindNewPipeAndPassReceiver()); } - cdm_provider_->CreateCdm(key_system, std::move(cdm_request)); + media_resource_provider_->CreateCdm(key_system, std::move(cdm_request)); } } // namespace media
diff --git a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h index 408909b..7411e11 100644 --- a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h +++ b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h
@@ -6,7 +6,7 @@ #define MEDIA_FUCHSIA_CDM_CLIENT_MOJO_FUCHSIA_CDM_PROVIDER_H_ #include "media/fuchsia/cdm/fuchsia_cdm_provider.h" -#include "media/fuchsia/mojom/fuchsia_cdm_provider.mojom.h" +#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h" #include "mojo/public/cpp/bindings/remote.h" namespace blink { @@ -34,7 +34,8 @@ private: blink::BrowserInterfaceBrokerProxy* const interface_broker_; - mojo::Remote<media::mojom::FuchsiaCdmProvider> cdm_provider_; + mojo::Remote<media::mojom::FuchsiaMediaResourceProvider> + media_resource_provider_; }; } // namespace media
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc b/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc index 942c1fae..1bef53c 100644 --- a/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc +++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc
@@ -137,6 +137,8 @@ return {}; } +FuchsiaCdmManager* g_fuchsia_cdm_manager_instance = nullptr; + } // namespace // Manages individual KeySystem connections. Provides data stores and @@ -263,6 +265,11 @@ base::flat_map<base::FilePath, DataStoreId> data_store_ids_by_path_; }; +// static +FuchsiaCdmManager* FuchsiaCdmManager::GetInstance() { + return g_fuchsia_cdm_manager_instance; +} + FuchsiaCdmManager::FuchsiaCdmManager( CreateKeySystemCallbackMap create_key_system_callbacks_by_name, base::FilePath cdm_data_path, @@ -279,9 +286,15 @@ // start. if (cdm_data_quota_bytes_) ApplyCdmStorageQuota(cdm_data_path_, *cdm_data_quota_bytes_); + + DCHECK(!g_fuchsia_cdm_manager_instance); + g_fuchsia_cdm_manager_instance = this; } -FuchsiaCdmManager::~FuchsiaCdmManager() = default; +FuchsiaCdmManager::~FuchsiaCdmManager() { + DCHECK_EQ(g_fuchsia_cdm_manager_instance, this); + g_fuchsia_cdm_manager_instance = nullptr; +} void FuchsiaCdmManager::CreateAndProvision( const std::string& key_system,
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager.h b/media/fuchsia/cdm/service/fuchsia_cdm_manager.h index 6e74192..8d3769da 100644 --- a/media/fuchsia/cdm/service/fuchsia_cdm_manager.h +++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager.h
@@ -35,6 +35,8 @@ using CreateKeySystemCallbackMap = base::flat_map<std::string, CreateKeySystemCallback>; + static FuchsiaCdmManager* GetInstance(); + // |cdm_data_quota_bytes| is currently only applied once, when the manager is // created. FuchsiaCdmManager(
diff --git a/media/fuchsia/mojom/BUILD.gn b/media/fuchsia/mojom/BUILD.gn index bb2f01f3..3918575 100644 --- a/media/fuchsia/mojom/BUILD.gn +++ b/media/fuchsia/mojom/BUILD.gn
@@ -4,8 +4,8 @@ import("//mojo/public/tools/bindings/mojom.gni") -mojom("cdm_provider") { - sources = [ "fuchsia_cdm_provider.mojom" ] +mojom("fuchsia_media_resource_provider") { + sources = [ "fuchsia_media_resource_provider.mojom" ] export_class_attribute_blink = "BLINK_PLATFORM_EXPORT" export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1" @@ -19,7 +19,7 @@ move_only = true }, ] - traits_headers = [ "fuchsia_cdm_provider_mojom_traits.h" ] + traits_headers = [ "fuchsia_media_resource_provider_mojom_traits.h" ] traits_public_deps = [ "//fuchsia/mojom:traits", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.media.drm",
diff --git a/media/fuchsia/mojom/fuchsia_cdm_provider.mojom b/media/fuchsia/mojom/fuchsia_media_resource_provider.mojom similarity index 78% rename from media/fuchsia/mojom/fuchsia_cdm_provider.mojom rename to media/fuchsia/mojom/fuchsia_media_resource_provider.mojom index ac6eadd..a91ba32b 100644 --- a/media/fuchsia/mojom/fuchsia_cdm_provider.mojom +++ b/media/fuchsia/mojom/fuchsia_media_resource_provider.mojom
@@ -10,9 +10,9 @@ handle<platform> request; }; -// Interface used by the render to connect -// fuchsia::media::drm::ContentDecryptionModule. Instances are document-scoped. -interface FuchsiaCdmProvider { +// Interface used by the renderer to connect to CDM and mediacodec resources. +// Instances are document-scoped. +interface FuchsiaMediaResourceProvider { // Create connection to fuchsia::media::drm::ContentDecryptionModule for // |key_system|. Implementation should make sure the persistent storage is // isolated per web origin.
diff --git a/media/fuchsia/mojom/fuchsia_cdm_provider_mojom_traits.h b/media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h similarity index 72% rename from media/fuchsia/mojom/fuchsia_cdm_provider_mojom_traits.h rename to media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h index dd44fa5..30b18a0 100644 --- a/media/fuchsia/mojom/fuchsia_cdm_provider_mojom_traits.h +++ b/media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.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 MEDIA_FUCHSIA_MOJOM_FUCHSIA_CDM_PROVIDER_MOJOM_TRAITS_H_ -#define MEDIA_FUCHSIA_MOJOM_FUCHSIA_CDM_PROVIDER_MOJOM_TRAITS_H_ +#ifndef MEDIA_FUCHSIA_MOJOM_FUCHSIA_MEDIA_RESOURCE_PROVIDER_MOJOM_TRAITS_H_ +#define MEDIA_FUCHSIA_MOJOM_FUCHSIA_MEDIA_RESOURCE_PROVIDER_MOJOM_TRAITS_H_ #include <fuchsia/media/drm/cpp/fidl.h> @@ -21,4 +21,4 @@ } // namespace mojo -#endif // MEDIA_FUCHSIA_MOJOM_FUCHSIA_CDM_PROVIDER_MOJOM_TRAITS_H_ +#endif // MEDIA_FUCHSIA_MOJOM_FUCHSIA_MEDIA_RESOURCE_PROVIDER_MOJOM_TRAITS_H_
diff --git a/media/gpu/buffer_validation.cc b/media/gpu/buffer_validation.cc index 24c432c..66499f0b3 100644 --- a/media/gpu/buffer_validation.cc +++ b/media/gpu/buffer_validation.cc
@@ -66,7 +66,9 @@ << coded_size.ToString(); return false; } - if (pixel_format != PIXEL_FORMAT_I420 && pixel_format != PIXEL_FORMAT_NV12 && + // YV12 is used by ARC++ on MTK8173. Consider removing it. + if (pixel_format != PIXEL_FORMAT_I420 && pixel_format != PIXEL_FORMAT_YV12 && + pixel_format != PIXEL_FORMAT_NV12 && pixel_format != PIXEL_FORMAT_P016LE) { VLOG(1) << "Unsupported: " << pixel_format; return false;
diff --git a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc index 95beb54f..4a8d771 100644 --- a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc +++ b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
@@ -372,9 +372,14 @@ surface->id(), surface->size(), surface->format(), /*release_cb=*/base::DoNothing()); - // We should call vaSyncSurface() when passing surface between contexts. See: - // https://lists.01.org/pipermail/intel-vaapi-media/2019-June/000131.html - if (!vpp_vaapi_wrapper_->SyncSurface(surface->id())) { + // We should call vaSyncSurface() when passing surface between contexts, but + // on Intel platform, we don't have to call vaSyncSurface() because the + // underlying drivers handle synchronization between different contexts. See: + // https://lists.01.org/hyperkitty/list/intel-vaapi-media@lists.01.org/message/YNFLDHHHQM2ZBFPMH7D3U6GLMOELHPFL/ + const bool is_intel_backend = + VaapiWrapper::GetImplementationType() == VAImplementation::kIntelI965 || + VaapiWrapper::GetImplementationType() == VAImplementation::kIntelIHD; + if (!is_intel_backend && !vpp_vaapi_wrapper_->SyncSurface(surface->id())) { VLOGF(1) << "Cannot sync VPP input surface"; return false; }
diff --git a/mojo/public/tools/mojom/mojom/generate/translate.py b/mojo/public/tools/mojom/mojom/generate/translate.py index f3c666d..6f4b871 100644 --- a/mojo/public/tools/mojom/mojom/generate/translate.py +++ b/mojo/public/tools/mojom/mojom/generate/translate.py
@@ -137,9 +137,13 @@ if attribute_list is None: return None assert isinstance(attribute_list, ast.AttributeList) - # TODO(vtl): Check for duplicate keys here. - return dict( - [(attribute.key, attribute.value) for attribute in attribute_list]) + attributes = dict() + for attribute in attribute_list: + if attribute.key in attributes: + raise Exception("Duplicate key (%s) in attribute list" % attribute.key) + else: + attributes[attribute.key] = attribute.value + return attributes builtin_values = frozenset([
diff --git a/mojo/public/tools/mojom/mojom/generate/translate_unittest.py b/mojo/public/tools/mojom/mojom/generate/translate_unittest.py index 5c9300b..95a916d 100644 --- a/mojo/public/tools/mojom/mojom/generate/translate_unittest.py +++ b/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
@@ -88,3 +88,19 @@ ]) with self.assertRaises(Exception): translate.OrderedModule(tree, "mojom_tree", []) + + def testDuplicateAttributesException(self): + tree = ast.Mojom(None, ast.ImportList(), [ + ast.Union( + "FakeUnion", + ast.AttributeList([ + ast.Attribute("key1", "value"), + ast.Attribute("key1", "value") + ]), + ast.UnionBody([ + ast.UnionField("a", None, None, "int32"), + ast.UnionField("b", None, None, "string") + ])) + ]) + with self.assertRaises(Exception): + translate.OrderedModule(tree, "mojom_tree", [])
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 77d4fdb9..23d84725 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -4653,7 +4653,6 @@ { "name": "dereferenced.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "devh.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "devolution.ws", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "die-blahuts.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "diegelernten.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dmlogic.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dmwall.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5211,7 +5210,6 @@ { "name": "kakao-karten.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kitakemon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "leinir.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "lepont.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "luom.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lyx.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "martinp.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8354,7 +8352,6 @@ { "name": "florence.uk.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "florent-tatard.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "florian-thie.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "floriankeller.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flyaces.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fnordserver.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fokkusu.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -13891,7 +13888,6 @@ { "name": "leakreporter.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jva-wuerzburg.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "komischkeszeug.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "layer8.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lca-pv.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "klebetape.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "leblanc.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16080,7 +16076,6 @@ { "name": "arewedubstepyet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "arados.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "artlifeisgood.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "aschaefer.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aluminium-scaffolding.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "asafilm.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aparaatti.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19867,7 +19862,6 @@ { "name": "safe.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "romarin.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "reinaldudrasfamily.ee", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rugs.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rodevlaggen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "robert-flynn.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "riverweb.gr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20718,7 +20712,6 @@ { "name": "ekedp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "electionsdatabase.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "emmagraystore.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "emmaliddell.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "emperor.blog", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "englishyamal.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "enjoymayfield.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24024,7 +24017,6 @@ { "name": "scwilliams.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "scwilliams.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sdia.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sdvx.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "seaholmwines.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sealtitebasement.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "seans.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26068,7 +26060,6 @@ { "name": "infinity.to", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "intradayseasonals.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "intellar.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "irugs.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "instagramtweet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "int-ext-design.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "innolabfribourg.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32335,7 +32326,6 @@ { "name": "weinbergerlawgroup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wellcom.co.il", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wellnesscheck.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "welzijnkoggenland.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "werkemotion.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wesreportportal.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "weyland.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34194,7 +34184,6 @@ { "name": "skhire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skuldwyrm.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skylineservers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "skype.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skys-entertainment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skyzimba.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "slavasveta.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36395,7 +36384,6 @@ { "name": "bytema.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bytema.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "caarecord.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cadams.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "calcedge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "campingskyhooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canker.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37363,7 +37351,6 @@ { "name": "sarahplusdrei.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sasrobotics.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sativatunja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "saxeandthecity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sbrouwer.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schollbox.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schwerkraftlabor.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39076,7 +39063,6 @@ { "name": "proprietairesmaisons.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pycrc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quantolytic.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "quizl.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "racheldiensthuette.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reachhead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reactor92.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39130,7 +39116,6 @@ { "name": "songsmp3.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "songsmp3.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "songsmp3.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "soraharu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "soulmating.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "souqtajmeel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "spazturtle.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39222,7 +39207,6 @@ { "name": "vgchat.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vinnie.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "visualizing.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vitalityscience.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vitalware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vorlage-musterbriefe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vorlage-mustervertrag.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39781,7 +39765,6 @@ { "name": "psdreams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pst.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "psytrance-pro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "punte-juwelier.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "q123123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quarkdose.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "questions-admin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41559,7 +41542,6 @@ { "name": "elevator.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elo.fyi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elonaspitze.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "elrinconderovica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elsagradocoran.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elshou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "emiliendevos.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42043,7 +42025,6 @@ { "name": "xserownia.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xserownia.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xtrainsights.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xywing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yanbao.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ygcdyf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yiffy.tips", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42435,7 +42416,6 @@ { "name": "kaikei7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kcmicapital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kforesund.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kinderchor-bayreuth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kjg-ummeln.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kobejet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kooliveeb.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -43328,7 +43308,6 @@ { "name": "bgtoyou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bh-oberland.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bit.biz.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bithap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bitlo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bitlo.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bitlo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46793,7 +46772,6 @@ { "name": "degosoft.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digital1world.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dipalma.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dissieux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "drchrislivingston.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dsanraffleshangbai.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dwi-sued.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48868,7 +48846,6 @@ { "name": "cathyjf.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cathyjf.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cathyjfitzpatrick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cesantias.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ceta.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chenna.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chr0me.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -49957,7 +49934,6 @@ { "name": "suttacentral.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swqa.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "syntheticgrassliving.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "talentwall.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tam-moon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tannerwilliamson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tar-mag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51361,7 +51337,6 @@ { "name": "treussart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tribaljusticeandsafety.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trix360.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ulitroyo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "usaseanconnect.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "usdoj.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "userra.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -52947,7 +52922,6 @@ { "name": "addydari.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adlignum.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adonizer.science", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "advanceddisposables.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adventurousway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ae-dir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ae-dir.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55218,9 +55192,6 @@ { "name": "poptimize.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prateep.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "preme.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pretor.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pretor.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pretorcup.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "primananda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proformer.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "propertysales-almeria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58931,7 +58902,6 @@ { "name": "devtoys.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dimagrimentoincorso.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "doggo.dance", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "download.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dronesz.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dutchsailors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ealadel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61099,7 +61069,6 @@ { "name": "ixanis.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jancukers.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jesuisunpapageek.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jetfirenetworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jiji.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jiji.com.gh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jiji.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -63689,7 +63658,6 @@ { "name": "londonindustry.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lsiq.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "luckystorevn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "madsstorm.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "manicuradegel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "manicuradegel.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mariafernanda.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70187,7 +70155,6 @@ { "name": "yantox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yapan8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yaws.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yellowsquid.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yemenlink.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yenbainet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yeniexpo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -72495,7 +72462,6 @@ { "name": "bhat.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bibliology.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biggerpicture.agency", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bodegasvirei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brandfolder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "broadbandchoices.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brols.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -73701,7 +73667,6 @@ { "name": "holacbdoils.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hongbomiao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "howmanypeoplearethereinthe.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "howmanypeoplearethereintheworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "huntcraft.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hurbascooter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hydra.ly", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -73802,7 +73767,6 @@ { "name": "pidibagrik.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "plandegralba.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "plasticosbiobasados.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "platformlms.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "plusreed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "politsei.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pragata.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -73895,7 +73859,6 @@ { "name": "acicj.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acs-nettoyage-entretien-immeuble.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "actionverb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ae86.plus", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aeroalbrook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "agendaspectacles.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "agktest1.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -74142,7 +74105,6 @@ { "name": "senu.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "serv.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "serveradmin.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "setxrm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sidsun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sieumod.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sign.dog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -74750,7 +74712,6 @@ { "name": "nocloud.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nogradhont.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "objectif-securite.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "officezoneonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "okkhor52.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "olive.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ollies.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -76231,7 +76192,6 @@ { "name": "maisvitaminas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "maisy.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mandilabeachhotel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "manitaggarwal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marjonruns.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marvin.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marvnet.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77395,7 +77355,6 @@ { "name": "rolandoredi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "royalpratapniwas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rssfeedblast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "rubenjromo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "saintanthonylakin.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sanogym.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "saorview.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77728,7 +77687,6 @@ { "name": "legend-v.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lexautoservice.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "limasartes.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "listisima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "livechat-ag777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lojas25online.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lonelyhaoss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79172,7 +79130,6 @@ { "name": "argyrakis.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arhitekti.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artikel9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "artisan-emmanuel.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aseth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aussiestories.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "awlgolf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81111,7 +81068,6 @@ { "name": "saito-koken.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sandton-plumbing.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "savejobsshoplocal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scheidingspuntlansingerland.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scholz-kallies.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scriptic.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securityhandbook.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81698,7 +81654,6 @@ { "name": "techday.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techvrse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tehranlittmann.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "telegram-sms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "teleportweb.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tenfeetsquare.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "termin-online.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83272,13 +83227,11 @@ { "name": "jimsefton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jobastudio.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "joyousisle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jrjuristen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jrstehlik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jrstehlik.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "justacoupleofclarkes.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "justninja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kadenba.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kakuch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kashrutbaking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kingnascholing.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kitchenpad.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84636,7 +84589,6 @@ { "name": "apix.uz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "app-scantech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "appmeucredito.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "appuntidallarete.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arcadegames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ardiandinar.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ariamovie.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -85050,7 +85002,6 @@ { "name": "hotdates18.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hothub.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "howunadeydoam.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hrkenterprise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hucklebucks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hughfitzgerald.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "humannaturelandscapes.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -85663,7 +85614,6 @@ { "name": "userbase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "usolvit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vanhatten.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vannoordgouda.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vaselineoel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "veganenumbers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vegculinary.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89527,7 +89477,6 @@ { "name": "diamondcontent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digital-insure.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digitalgeek.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dimism.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "directfitnesssolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "discus.fish", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "distribuidoradecierres.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89950,7 +89899,6 @@ { "name": "insomniac.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "interactiveliterature.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iorgroup.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "iqbalmauludy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iqos.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isustain.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ithot.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -99967,7 +99915,6 @@ { "name": "mercurycards.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meterinsight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "micah.soy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "micaritafeliz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "michelgolfier.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "migrainereliefplan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mindomo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -100220,7 +100167,6 @@ { "name": "charolopezatelier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chataumateje.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cheng.pet", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "chocolatebelga.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "christianvanos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "civil-works-sri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cl-brands.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -100305,7 +100251,6 @@ { "name": "fulltextarchive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fusionauth.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fyllehack.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gbsapri.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "geekgirltech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gethyas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gilloteaux.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -101273,7 +101218,6 @@ { "name": "codydostal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "coldecan.edu.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "condizionatore-portatile.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "congregacionmitacol.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "consul-coton.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "corvettesalvage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "crowdpress.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -102564,7 +102508,6 @@ { "name": "nationsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ndmibiza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "neon-lover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "neotracker.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nerta.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netroworx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ngo4ngo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -102708,7 +102651,6 @@ { "name": "ultrageilo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unitedmethodistchurch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unsiteweb.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "useon.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "userstation.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uzidesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vaartjesboten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108844,7 +108786,6 @@ { "name": "modapush.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moebel-starck.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "montserratoptics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "morbitiles.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mrdehkar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mtv.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mu-thunder.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110398,7 +110339,6 @@ { "name": "theauthenticdad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theclearingnw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thecontentexpertel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thedentalstudiomiami.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thedevilsbrigade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thenathanmethod.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thenviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110738,7 +110678,6 @@ { "name": "d21laxujm54z8h.cloudfront.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d58beu28.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dailybihar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dailyphototips.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "daiwa-union.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "databricks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "datatube.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110843,8 +110782,6 @@ { "name": "flexmedia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flowersandplantsco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flydoc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fmorales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fmorales.com.ni", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fondationo2.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "forbesmarshall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ford.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -112174,7 +112111,6 @@ { "name": "kankerpannekoek.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "khalti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kokomo.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "komplexlysimple.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "komputersat.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koobin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kovered.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -112300,7 +112236,6 @@ { "name": "schu.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schwarzholdingsgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sdruzeniprovltavu.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "secopsolution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seonurse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "serve.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "setmore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -114282,7 +114217,6 @@ { "name": "bauer-reininghorses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bcomm.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beeldbankgent.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "beemenergy.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beer-sheva.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "behmmjc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bendelllawfirm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -114461,7 +114395,6 @@ { "name": "escrowalliance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "esm.run", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "espenandersen.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eucybernet.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "everythinglidia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "examesrush.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "excellence.corsica", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -114831,7 +114764,6 @@ { "name": "reklamaios.pp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "relevanttomyinterests.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "repalanca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "republic.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "resulttado.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rewardscout.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rez.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -116887,7 +116819,6 @@ { "name": "swamiclub.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sweetfadays.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swet.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "swiss-sale.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swissmarket24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "symbolics.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "symstar.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -117410,11 +117341,9 @@ { "name": "giyav.org.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "glassact.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "glasstechnics.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "glavfundament.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "globalexcelsummit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "globalhubb.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gmsurveyingms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gndmillwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "go-go.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gocadservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gohelixit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -118154,7 +118083,6 @@ { "name": "whatswrong.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wheelycool.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wheelycoolgear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wherefish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whiteantelopeinteriors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whocrushonme.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wikibooks.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -120302,7 +120230,6 @@ { "name": "itfall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itleaked.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itlogic.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "itnrd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itrew.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itsmohitchahal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itsnotnot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -120770,7 +120697,6 @@ { "name": "marmaladetoast.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marmo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marocweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "marokkaansearganolie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marquisepools.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marsilioblack.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "martialartsbrownsplains.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -121460,7 +121386,6 @@ { "name": "regulative.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reikimaster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reinodemurcia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "reishihealthcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reklamirui.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "relatosypoesias.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "releases.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -127811,7 +127736,6 @@ { "name": "blackestdespondency.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blackheads.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blago-sostoyanie.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "blauesschwarz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blazefire.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blixpage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blueswanbookkeeping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -131233,7 +131157,6 @@ { "name": "v2speed.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "valdres.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "valheim.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vanarok.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "varlin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vasilijeojdanic.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vazgaming.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -132512,7 +132435,6 @@ { "name": "zebraonegallery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zerobelow.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zerobelow.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "zoom-eco.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zootsys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zsi.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "11tv.dp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -136675,7 +136597,6 @@ { "name": "izumrudniy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jadiercms.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jamesbromberger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jantakareporter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jaschaa.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jayspage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jelobox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -138006,7 +137927,6 @@ { "name": "turbosim.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "turoktv.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tuyensinhcanuoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tzstamp.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uinvest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ulimports.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ulsprouts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -141965,7 +141885,6 @@ { "name": "arbradio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "argosasist.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aridireksiyon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "armazon.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arp-arena.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aryescommercial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aryesgroup.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -147100,7 +147019,6 @@ { "name": "tgt.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thandanhapkhau.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theartwolf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thedailyreporteronline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thekittivibe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thematchless.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theotherconcept.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -147139,7 +147057,6 @@ { "name": "two-many.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tylerpayne.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "typesolution.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tzhsoj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uatuning.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uavis.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "udilicitana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -148822,7 +148739,6 @@ { "name": "mediaverse.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meinhard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "menzcentraal.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "meopta.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "metalmaintenance.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "metanoiaphotography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "micromagic.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -148936,7 +148852,6 @@ { "name": "schermen-en.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "school91.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scommessalegale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scraperhireaustralia.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "secadoresdepelo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "secvuln.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seejay.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -150658,7 +150573,6 @@ { "name": "prachiiimohite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "primeone.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "print3dgifts.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pro-box.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "productsafety.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "progrillcleaning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "propeld.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -151807,7 +151721,6 @@ { "name": "websiteleichtgemacht.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webstaurant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webstaurantstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "weegshop.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wehostyou360.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weimingsci.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "welspunindia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -153111,7 +153024,6 @@ { "name": "jitendrapatro.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jkmoving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jktu.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jobnas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "johncleary.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "joinmatrix.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jourdespa.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -153971,7 +153883,6 @@ { "name": "oursportscentral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oxizonia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "panamasportsfactory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "paven.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "paycaptain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "paylocal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pentopolimer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -155965,7 +155876,6 @@ { "name": "denverautoinsurancecompany.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "depressionadvice.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "depthsofdepravity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "der-andere-film.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deratisation-prix.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deratisation.paris", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "derhaeuptling.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -155981,7 +155891,6 @@ { "name": "desvan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deurwaarderhelmond.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "devanstavern.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "developed-sd.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "developpeur-web2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "devoted-atheist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "devs-from.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -156006,7 +155915,6 @@ { "name": "digicomtel.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digimax.dental", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digisign.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "digital24.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digitaldruck.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digitale-bibliothek.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digitalinberlin.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -157282,7 +157190,6 @@ { "name": "jacov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jad.so", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jadehairstyle.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jaehyeon.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jaehyeonit.ltd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jagogame.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jahidhasanmurad.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -157759,7 +157666,6 @@ { "name": "lower-level.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lower.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lowriderz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lpnm.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lsxteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ltt-europe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lubosabo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -158393,7 +158299,6 @@ { "name": "office-basilique.notaires.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "officerjones.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "officialdubaidev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "officialnewcapital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "officialniledevelopments.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "officialpyramids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "officialtajmisr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -159239,7 +159144,6 @@ { "name": "susumulus.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "suziepachecoart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "svtv.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "swami-krishnananda.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swarovskijewelry.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swilagod.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swot-digital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -160273,6 +160177,85 @@ { "name": "narodne.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ncctouring.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zmsp.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "0x1.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "12lasee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "18nsj.tokyo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1901.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2022etmoi.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "22nd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "24webserver.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "27skycake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3eyonetim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3ml.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "404888.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4dimension.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4f.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4f.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.lv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4fstore.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "514.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5tiptop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "7654654.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "807software.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "893fm.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "97display.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a12k.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a2zcatalog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aaltocapital.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aaltocapital.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aarhus-protein.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abcum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abdul.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abhijit.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abilities-inc.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ablx.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abraxas-apis.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abraxas-apps.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absconse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absintheaura.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abstractqatar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abys.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accademiadelgolden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accurxinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ace0328.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aceprogramme.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "achildshome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "achildshome.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "actifii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "actions.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "activat3rs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "activetk.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ad-education.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adam.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adamsapic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adarshthapa.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adc-dentalcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addictstore.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addspi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adhdsnap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adkinvest.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "admingateway.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "administradoresdefincasvalencia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adnempresa.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adressendata.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "advancedfueladditives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "advanceoptical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "advc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "advocaat-dejonge.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aesthetix.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aevo-vergleich.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "affairs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "affiliatebitz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "affine.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "affle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "affordable.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afoikrali.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, // END OF 1-YEAR BULK HSTS ENTRIES // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/services/data_decoder/public/cpp/safe_web_bundle_parser.cc b/services/data_decoder/public/cpp/safe_web_bundle_parser.cc index ac1d849..8f9e227 100644 --- a/services/data_decoder/public/cpp/safe_web_bundle_parser.cc +++ b/services/data_decoder/public/cpp/safe_web_bundle_parser.cc
@@ -53,7 +53,7 @@ nullptr, web_package::mojom::BundleMetadataParseError::New( web_package::mojom::BundleParseErrorType::kParserInternalError, - GURL() /* fallback_url */, kConnectionError)); + kConnectionError)); return; } metadata_callback_ = std::move(callback); @@ -105,7 +105,7 @@ .Run(nullptr, web_package::mojom::BundleMetadataParseError::New( web_package::mojom::BundleParseErrorType::kParserInternalError, - GURL() /* fallback_url */, kConnectionError)); + kConnectionError)); for (auto& callback : response_callbacks_) std::move(callback.second) .Run(nullptr,
diff --git a/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc b/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc index 37b4828f..ac01dd2 100644 --- a/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc +++ b/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc
@@ -163,8 +163,7 @@ base::test::TestFuture<web_package::mojom::BundleResponsePtr, web_package::mojom::BundleResponseParseErrorPtr> response_future; - parser.ParseResponse(entry.second->response_locations[0]->offset, - entry.second->response_locations[0]->length, + parser.ParseResponse(entry.second->offset, entry.second->length, response_future.GetCallback()); auto [response, response_error] = response_future.Take(); ASSERT_TRUE(response);
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index ddc64c1..8bee660 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -177,12 +177,6 @@ const base::Feature kWebSocketReassembleShortMessages{ "WebSocketReassembleShortMessages", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enable support for ACCEPT_CH H2/3 frame as part of Client Hint Reliability. -// See: -// https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02#section-4.3 -const base::Feature kAcceptCHFrame{"AcceptCHFrame", - base::FEATURE_ENABLED_BY_DEFAULT}; - const base::Feature kSCTAuditingRetryReports{"SCTAuditingRetryReports", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h index 339a54c..b7ed549 100644 --- a/services/network/public/cpp/features.h +++ b/services/network/public/cpp/features.h
@@ -65,9 +65,6 @@ extern const base::Feature kWebSocketReassembleShortMessages; COMPONENT_EXPORT(NETWORK_CPP) -extern const base::Feature kAcceptCHFrame; - -COMPONENT_EXPORT(NETWORK_CPP) extern const base::Feature kSCTAuditingRetryReports; COMPONENT_EXPORT(NETWORK_CPP)
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index 74365833..69fe6a6 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc
@@ -1128,8 +1128,7 @@ return net::ERR_FAILED; } - if (!accept_ch_frame_observer_ || info.accept_ch_frame.empty() || - !base::FeatureList::IsEnabled(features::kAcceptCHFrame)) { + if (!accept_ch_frame_observer_ || info.accept_ch_frame.empty()) { return net::OK; }
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc index 1b128f16..986ff73b 100644 --- a/services/network/url_loader_unittest.cc +++ b/services/network/url_loader_unittest.cc
@@ -613,8 +613,7 @@ net::URLRequestFailedJob::AddUrlHandler(); scoped_feature_list_.InitWithFeatures( - /*enabled_features=*/{features::kAcceptCHFrame, - net::features::kRecordRadioWakeupTrigger}, + /*enabled_features=*/{net::features::kRecordRadioWakeupTrigger}, /*disabled_features=*/{}); } ~URLLoaderTest() override {
diff --git a/services/network/web_bundle/web_bundle_url_loader_factory.cc b/services/network/web_bundle/web_bundle_url_loader_factory.cc index 1859004..12355de 100644 --- a/services/network/web_bundle/web_bundle_url_loader_factory.cc +++ b/services/network/web_bundle/web_bundle_url_loader_factory.cc
@@ -679,12 +679,9 @@ loader->OnFail(net::ERR_INVALID_WEB_BUNDLE); return; } - // Currently, we just return the first response for the URL. - // TODO(crbug.com/1082020): Support variant matching. - auto& location = it->second->response_locations[0]; parser_->ParseResponse( - location->offset, location->length, + it->second->offset, it->second->length, base::BindOnce(&WebBundleURLLoaderFactory::OnResponseParsed, weak_ptr_factory_.GetWeakPtr(), loader->GetWeakPtr())); }
diff --git a/services/network/web_bundle/web_bundle_url_loader_factory_unittest.cc b/services/network/web_bundle/web_bundle_url_loader_factory_unittest.cc index 3ee5967..b0d05e2 100644 --- a/services/network/web_bundle/web_bundle_url_loader_factory_unittest.cc +++ b/services/network/web_bundle/web_bundle_url_loader_factory_unittest.cc
@@ -79,15 +79,6 @@ return builder.CreateBundle(); } -std::vector<uint8_t> CreateB1Bundle() { - web_package::WebBundleBuilder builder(kResourceUrl, "" /* manifest_url */, - web_package::BundleVersion::kB1); - builder.AddExchange(kResourceUrl, - {{":status", "200"}, {"content-type", "text/plain"}}, - "body"); - return builder.CreateBundle(); -} - class TestWebBundleHandle : public mojom::WebBundleHandle { public: explicit TestWebBundleHandle( @@ -545,27 +536,4 @@ "WebBundleURLLoaderFactory: Bundle URL does not match")); } -TEST_F(WebBundleURLLoaderFactoryTest, DeprecatedBundleVersion) { - WriteBundle(CreateB1Bundle()); - FinishWritingBundle(); - - EXPECT_CALL(*devtools_observer_, - OnSubresourceWebBundleMetadata(kBundleRequestId, - ElementsAre(GURL(kResourceUrl)))); - EXPECT_CALL(*devtools_observer_, - OnSubresourceWebBundleInnerResponse( - kResourceRequestId, GURL(kResourceUrl), - Optional(std::string(kBundleRequestId)))); - - auto request = StartRequest(GURL(kResourceUrl), kResourceRequestId); - request.client->RunUntilComplete(); - - EXPECT_EQ(net::OK, request.client->completion_status().error_code); - EXPECT_EQ(last_bundle_error()->first, - mojom::WebBundleErrorType::kDeprecationWarning); - EXPECT_EQ(last_bundle_error()->second, - "WebBundle format \"b1\" is deprecated. See migration guide at " - "https://bit.ly/3rpDuEX."); -} - } // namespace network
diff --git a/services/services_strings.grd b/services/services_strings.grd index 059d940..a15a5b1 100644 --- a/services/services_strings.grd +++ b/services/services_strings.grd
@@ -21,6 +21,7 @@ <output filename="services_strings_bs.pak" type="data_package" lang="bs" /> <output filename="services_strings_ca.pak" type="data_package" lang="ca" /> <output filename="services_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="services_strings_cy.pak" type="data_package" lang="cy" /> <output filename="services_strings_da.pak" type="data_package" lang="da" /> <output filename="services_strings_de.pak" type="data_package" lang="de" /> <output filename="services_strings_el.pak" type="data_package" lang="el" />
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 8dfe0d9..a9f6fa9 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -8178,7 +8178,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -8682,7 +8682,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 6f108ce4..183244e 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -45929,7 +45929,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -46433,7 +46433,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -46941,7 +46941,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -47445,7 +47445,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -48020,7 +48020,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -48524,7 +48524,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -49099,7 +49099,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -49603,7 +49603,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.83" + "revision": "version:100.0.4896.84" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index ce6e0ad0..dffa866 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -483,7 +483,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M100', - 'revision': 'version:100.0.4896.83', + 'revision': 'version:100.0.4896.84', } ], }, @@ -627,7 +627,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M100', - 'revision': 'version:100.0.4896.83', + 'revision': 'version:100.0.4896.84', } ], }, @@ -771,7 +771,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M100', - 'revision': 'version:100.0.4896.83', + 'revision': 'version:100.0.4896.84', } ], },
diff --git a/testing/scripts/finch.gni b/testing/scripts/finch.gni index 30335dd..650e544 100644 --- a/testing/scripts/finch.gni +++ b/testing/scripts/finch.gni
@@ -26,6 +26,8 @@ data = [ "//build/android/", + "//build/skia_gold_common/", + "//testing/scripts/skia_gold_infra", "//testing/scripts/variations_smoke_test_data/", "//tools/android/", "$root_build_dir/pyproto/",
diff --git a/testing/scripts/run_finch_smoke_tests_android.py b/testing/scripts/run_finch_smoke_tests_android.py index 7404317..8a3529a3 100755 --- a/testing/scripts/run_finch_smoke_tests_android.py +++ b/testing/scripts/run_finch_smoke_tests_android.py
@@ -63,10 +63,9 @@ from devil.android.tools import system_app from devil.android.tools import webview_app from devil.utils import logging_common - from pylib.local.emulator import avd from py_utils.tempfile_ext import NamedTemporaryDirectory - +from skia_gold_infra.finch_skia_gold_properties import FinchSkiaGoldProperties from wpt_android_lib import add_emulator_args, get_device LOGCAT_FILTERS = [ @@ -251,7 +250,8 @@ default='stable', choices=['dev', 'canary', 'beta', 'stable'], help='Finch seed release channel') - + # Add arguments used by Skia Gold. + FinchSkiaGoldProperties.AddCommandLineArguments(parser) add_emulator_args(parser) script_common.AddDeviceArguments(parser) script_common.AddEnvironmentArguments(parser)
diff --git a/testing/scripts/run_variations_smoke_tests.py b/testing/scripts/run_variations_smoke_tests.py index 5d170af..a3b94029 100755 --- a/testing/scripts/run_variations_smoke_tests.py +++ b/testing/scripts/run_variations_smoke_tests.py
@@ -18,7 +18,7 @@ from functools import partial from http.server import SimpleHTTPRequestHandler from threading import Thread -from skia_gold_infra import finch_skia_gold_properties +from skia_gold_infra.finch_skia_gold_properties import FinchSkiaGoldProperties from skia_gold_infra import finch_skia_gold_session_manager import common @@ -358,16 +358,13 @@ logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser() parser.add_argument('--isolated-script-test-output', type=str) - parser.add_argument('--git-revision', type=str) - parser.add_argument('--gerrit-issue', type=int) - parser.add_argument('--gerrit-patchset', type=int) - parser.add_argument('--buildbucket-id', type=int) + FinchSkiaGoldProperties.AddCommandLineArguments(parser) args, rest = parser.parse_known_args() temp_dir = tempfile.mkdtemp() httpd = _start_local_http_server() manager = finch_skia_gold_session_manager.FinchSkiaGoldSessionManager( - temp_dir, finch_skia_gold_properties.FinchSkiaGoldProperties(args)) + temp_dir, FinchSkiaGoldProperties(args)) try: rc = _run_tests(temp_dir, manager, *rest) if args.isolated_script_test_output:
diff --git a/testing/test.gni b/testing/test.gni index 359b4c0..09dea6e 100644 --- a/testing/test.gni +++ b/testing/test.gni
@@ -254,6 +254,8 @@ "enable_multidex", "generate_final_jni", "product_config_java_packages", + "loadable_modules", + "loadable_module_deps", "min_sdk_version", "proguard_configs", "proguard_enabled", @@ -330,6 +332,9 @@ } else { deps = [] } + if (defined(loadable_module_deps)) { + deps += loadable_module_deps + } # Add the Java classes so that each target does not have to do it. if (_use_default_launcher) {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index d395263..6cb6b4f 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -4627,6 +4627,31 @@ ] } ], + "NeuralPalmRejectionModelV2AndAdaptiveHold": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "NeuralPalmRejectionAdaptiveHold_20220207", + "enable_features": [ + "EnableNeuralPalmAdaptiveHold", + "EnableNeuralPalmRejectionModelV2" + ] + }, + { + "name": "NeuralPalmRejectionModelV2_20220207", + "enable_features": [ + "EnableNeuralPalmRejectionModelV2" + ], + "disable_features": [ + "EnableNeuralPalmAdaptiveHold" + ] + } + ] + } + ], "NoWakeUpsForCanceledTasks": [ { "platforms": [ @@ -5279,31 +5304,6 @@ ] } ], - "PalmRejectionAdaptiveHold": [ - { - "platforms": [ - "chromeos" - ], - "experiments": [ - { - "name": "NeuralPalmRejectionAdaptiveHold_20220207", - "enable_features": [ - "EnableNeuralPalmAdaptiveHold", - "EnableNeuralPalmRejectionModelV2" - ] - }, - { - "name": "NeuralPalmRejectionModelV2_20220207", - "enable_features": [ - "EnableNeuralPalmRejectionModelV2" - ], - "disable_features": [ - "EnableNeuralPalmAdaptiveHold" - ] - } - ] - } - ], "ParkableImages": [ { "platforms": [ @@ -5987,24 +5987,6 @@ ] } ], - "ReadingListMessages": [ - { - "platforms": [ - "ios" - ], - "experiments": [ - { - "name": "Enabled", - "params": { - "javascript_only": "true" - }, - "enable_features": [ - "ReadingListMessages" - ] - } - ] - } - ], "ReduceOpsTaskSplitting": [ { "platforms": [ @@ -6658,7 +6640,7 @@ ] } ], - "SingleNTPRemoveExcessNTPs": [ + "SingleNTPRemoveExtraNTPs": [ { "platforms": [ "ios"
diff --git a/third_party/blink/public/strings/blink_accessibility_strings.grd b/third_party/blink/public/strings/blink_accessibility_strings.grd index 19a591f..f169563 100644 --- a/third_party/blink/public/strings/blink_accessibility_strings.grd +++ b/third_party/blink/public/strings/blink_accessibility_strings.grd
@@ -21,6 +21,7 @@ <output filename="blink_accessibility_strings_bs.pak" type="data_package" lang="bs" /> <output filename="blink_accessibility_strings_ca.pak" type="data_package" lang="ca" /> <output filename="blink_accessibility_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="blink_accessibility_strings_cy.pak" type="data_package" lang="cy" /> <output filename="blink_accessibility_strings_da.pak" type="data_package" lang="da" /> <output filename="blink_accessibility_strings_de.pak" type="data_package" lang="de" /> <output filename="blink_accessibility_strings_el.pak" type="data_package" lang="el" />
diff --git a/third_party/blink/public/strings/blink_strings.grd b/third_party/blink/public/strings/blink_strings.grd index 398967b..0294268 100644 --- a/third_party/blink/public/strings/blink_strings.grd +++ b/third_party/blink/public/strings/blink_strings.grd
@@ -57,6 +57,7 @@ <output filename="blink_strings_bs.pak" type="data_package" lang="bs" /> <output filename="blink_strings_ca.pak" type="data_package" lang="ca" /> <output filename="blink_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="blink_strings_cy.pak" type="data_package" lang="cy" /> <output filename="blink_strings_da.pak" type="data_package" lang="da" /> <output filename="blink_strings_de.pak" type="data_package" lang="de" /> <output filename="blink_strings_el.pak" type="data_package" lang="el" />
diff --git a/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc b/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc index 2aadbd7..116c61b 100644 --- a/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
@@ -5,6 +5,7 @@ #include "base/memory/ptr_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_cache.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/module_record_test.cc b/third_party/blink/renderer/bindings/core/v8/module_record_test.cc index 9cfc5ee..ca29db1 100644 --- a/third_party/blink/renderer/bindings/core/v8/module_record_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
@@ -281,7 +281,8 @@ ScriptEvaluationResult::ResultType::kSuccess); v8::Local<v8::Value> value = ClassicScript::CreateUnspecifiedScript("window.foo") - ->RunScriptAndReturnValue(&scope.GetWindow()); + ->RunScriptAndReturnValue(&scope.GetWindow()) + .GetSuccessValueOrEmpty(); ASSERT_TRUE(value->IsString()); EXPECT_EQ("bar", ToCoreString(v8::Local<v8::String>::Cast(value)));
diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/third_party/blink/renderer/bindings/core/v8/script_controller.cc index 8530b5d..5ad3d68 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_controller.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
@@ -36,6 +36,7 @@ #include <utility> #include "base/callback_helpers.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" #include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h" @@ -211,7 +212,8 @@ DCHECK_EQ(&window_->GetScriptController(), this); v8::HandleScope handle_scope(GetIsolate()); - v8::Local<v8::Value> v8_result = script->RunScriptAndReturnValue(window_); + v8::Local<v8::Value> v8_result = + script->RunScriptAndReturnValue(window_).GetSuccessValueOrEmpty(); UseCounter::Count(window_.Get(), WebFeature::kExecutedJavaScriptURL); // If executing script caused this frame to be removed from the page, we
diff --git a/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc index 17a46278..a9b9d72 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc
@@ -86,6 +86,12 @@ return value_; } +v8::Local<v8::Value> ScriptEvaluationResult::GetSuccessValueOrEmpty() const { + if (GetResultType() == ResultType::kSuccess) + return GetSuccessValue(); + return v8::Local<v8::Value>(); +} + v8::Local<v8::Value> ScriptEvaluationResult::GetExceptionForModule() const { #if DCHECK_IS_ON() DCHECK_EQ(script_type_, mojom::blink::ScriptType::kModule);
diff --git a/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h index 0515d6d..18c77df 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h +++ b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h
@@ -105,6 +105,9 @@ // promise for modules. v8::Local<v8::Value> GetSuccessValue() const; + // Returns the value when GetResultType() == kSuccess, or empty otherwise. + v8::Local<v8::Value> GetSuccessValueOrEmpty() const; + // Returns the exception thrown. // Can be called only when GetResultType() == kException. v8::Local<v8::Value> GetExceptionForModule() const;
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc index 0b9a0c9d..8744d2b 100644 --- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -9,6 +9,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_blob_info.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/unpacked_serialized_script_value.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" @@ -113,7 +114,8 @@ v8::Local<v8::Value> Eval(const String& source, V8TestingScope& scope) { return ClassicScript::CreateUnspecifiedScript(source) - ->RunScriptAndReturnValue(&scope.GetWindow()); + ->RunScriptAndReturnValue(&scope.GetWindow()) + .GetSuccessValueOrEmpty(); } String ToJSON(v8::Local<v8::Object> object, const V8TestingScope& scope) {
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc b/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc index df06a5be..9e96442 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc
@@ -224,8 +224,17 @@ UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.MainThread.Full.Atomic", "", event.main_thread_atomic); + // Report incremental marking/sweeping metrics: + UMA_HISTOGRAM_TIMES( + "V8.GC.Cycle.MainThread.Full.Incremental.Mark", + base::Microseconds( + event.main_thread_incremental.mark_wall_clock_duration_in_us)); + UMA_HISTOGRAM_TIMES( + "V8.GC.Cycle.MainThread.Full.Incremental.Sweep", + base::Microseconds( + event.main_thread_incremental.sweep_wall_clock_duration_in_us)); + // TODO(chromium:1154636): emit the following when they are populated: - // - event.main_thread_incremental // - event.objects // - event.memory @@ -260,6 +269,16 @@ UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.MainThread.Full.Atomic", ".Cpp", event.main_thread_atomic_cpp); + // Report incremental marking/sweeping metrics: + UMA_HISTOGRAM_TIMES( + "V8.GC.Cycle.MainThread.Full.Incremental.Mark.Cpp", + base::Microseconds( + event.main_thread_incremental_cpp.mark_wall_clock_duration_in_us)); + UMA_HISTOGRAM_TIMES( + "V8.GC.Cycle.MainThread.Full.Incremental.Sweep.Cpp", + base::Microseconds( + event.main_thread_incremental_cpp.sweep_wall_clock_duration_in_us)); + // Report size metrics: DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, object_size_before_histogram,
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_element_test.cc b/third_party/blink/renderer/bindings/modules/v8/v8_element_test.cc index fa149b2..032c095 100644 --- a/third_party/blink/renderer/bindings/modules/v8/v8_element_test.cc +++ b/third_party/blink/renderer/bindings/modules/v8/v8_element_test.cc
@@ -2,6 +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/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/core/script/classic_script.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -37,7 +38,8 @@ v8::Local<v8::Value> Eval(const String& source, V8TestingScope& scope) { return ClassicScript::CreateUnspecifiedScript(source) - ->RunScriptAndReturnValue(&scope.GetWindow()); + ->RunScriptAndReturnValue(&scope.GetWindow()) + .GetSuccessValueOrEmpty(); } TEST_F(V8ElementTest, SetAttributeOperationCallback) {
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder_test.cc b/third_party/blink/renderer/core/editing/finder/text_finder_test.cc index 298f043..350e63e 100644 --- a/third_party/blink/renderer/core/editing/finder/text_finder_test.cc +++ b/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/web/web_document.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/core/dom/comment.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -74,7 +75,8 @@ v8::Local<v8::Value> TextFinderTest::EvalJs(const std::string& script) { return ClassicScript::CreateUnspecifiedScript(script.c_str()) - ->RunScriptAndReturnValue(GetDocument().domWindow()); + ->RunScriptAndReturnValue(GetDocument().domWindow()) + .GetSuccessValueOrEmpty(); } Document& TextFinderTest::GetDocument() const {
diff --git a/third_party/blink/renderer/core/frame/dom_timer_test.cc b/third_party/blink/renderer/core/frame/dom_timer_test.cc index 9f7fc76b..1c66539 100644 --- a/third_party/blink/renderer/core/frame/dom_timer_test.cc +++ b/third_party/blink/renderer/core/frame/dom_timer_test.cc
@@ -12,6 +12,7 @@ #include "third_party/blink/public/common/switches.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/script/classic_script.h" @@ -64,7 +65,8 @@ v8::Local<v8::Value> EvalExpression(const char* expr) { return ClassicScript::CreateUnspecifiedScript(expr) - ->RunScriptAndReturnValue(GetDocument().domWindow()); + ->RunScriptAndReturnValue(GetDocument().domWindow()) + .GetSuccessValueOrEmpty(); } Vector<double> ToDoubleArray(v8::Local<v8::Value> value,
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc index e8d42782..9ee3d6b4 100644 --- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc +++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
@@ -23,6 +23,7 @@ #include "third_party/blink/public/web/web_local_frame_client.h" #include "third_party/blink/public/web/web_plugin.h" #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/core/dom/element_traversal.h" #include "third_party/blink/renderer/core/dom/ignore_opens_during_unload_count_incrementer.h" #include "third_party/blink/renderer/core/editing/editing_utilities.h" @@ -280,8 +281,9 @@ ClassicScript* classic_script = ClassicScript::CreateUnspecifiedScript( script_, ScriptSourceLocationType::kInternal, SanitizeScriptErrors::kDoNotSanitize); - return {classic_script->RunScriptInIsolatedWorldAndReturnValue(window, - world_id_)}; + return { + classic_script->RunScriptInIsolatedWorldAndReturnValue(window, world_id_) + .GetSuccessValueOrEmpty()}; } void JavaScriptIsolatedWorldRequest::Completed( @@ -879,7 +881,8 @@ v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); v8::Local<v8::Value> result = ClassicScript::CreateUnspecifiedScript(javascript) - ->RunScriptAndReturnValue(DomWindow()); + ->RunScriptAndReturnValue(DomWindow()) + .GetSuccessValueOrEmpty(); if (wants_result) { std::unique_ptr<WebV8ValueConverter> converter = @@ -921,12 +924,14 @@ SanitizeScriptErrors::kDoNotSanitize); if (world_id == DOMWrapperWorld::kMainWorldId) { - result = script->RunScriptAndReturnValue(DomWindow()); + result = + script->RunScriptAndReturnValue(DomWindow()).GetSuccessValueOrEmpty(); } else { CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId); CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit); result = - script->RunScriptInIsolatedWorldAndReturnValue(DomWindow(), world_id); + script->RunScriptInIsolatedWorldAndReturnValue(DomWindow(), world_id) + .GetSuccessValueOrEmpty(); } if (wants_result) {
diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc index 2e8964ee..0e10a85 100644 --- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc +++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/public/platform/web_vector.h" #include "third_party/blink/public/web/web_script_execution_callback.h" #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" @@ -174,11 +175,11 @@ // a foreign world. ClassicScript* classic_script = ClassicScript::CreateUnspecifiedScript( source, SanitizeScriptErrors::kDoNotSanitize); - v8::Local<v8::Value> script_value = + ScriptEvaluationResult result = world_id_ ? classic_script->RunScriptInIsolatedWorldAndReturnValue( window, world_id_) : classic_script->RunScriptAndReturnValue(window); - results.push_back(script_value); + results.push_back(result.GetSuccessValueOrEmpty()); } return results;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index 219038f..05f03ea 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -142,6 +142,7 @@ #include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h" #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h" #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/bindings/core/v8/source_location.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" @@ -932,7 +933,8 @@ return ClassicScript::CreateUnspecifiedScript( source_in, SanitizeScriptErrors::kDoNotSanitize) ->RunScriptInIsolatedWorldAndReturnValue(GetFrame()->DomWindow(), - world_id); + world_id) + .GetSuccessValueOrEmpty(); } void WebLocalFrameImpl::ClearIsolatedWorldCSPForTesting(int32_t world_id) { @@ -999,7 +1001,8 @@ const WebScriptSource& source) { DCHECK(GetFrame()); return ClassicScript::CreateUnspecifiedScript(source) - ->RunScriptAndReturnValue(GetFrame()->DomWindow()); + ->RunScriptAndReturnValue(GetFrame()->DomWindow()) + .GetSuccessValueOrEmpty(); } void WebLocalFrameImpl::RequestExecuteV8Function(
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc index 1f80dd0..a649940 100644 --- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -42,6 +42,7 @@ #include "third_party/blink/public/platform/web_data.h" #include "third_party/blink/public/resources/grit/inspector_overlay_resources_map.h" #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_inspector_overlay_host.h" #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h" @@ -1373,7 +1374,8 @@ script, ScriptSourceLocationType::kInspector) ->RunScriptAndReturnValue( To<LocalFrame>(OverlayMainFrame())->DomWindow(), - ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled); + ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled) + .GetSuccessValueOrEmpty(); return ToCoreStringWithUndefinedOrNullCheck(string); }
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc index 6ac25db6..db978ee 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -41,6 +41,7 @@ #include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/mojom/ad_tagging/ad_evidence.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/script_regexp.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document_timing.h"
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc index 1ecd636..56d6408 100644 --- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc +++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -805,6 +805,7 @@ const NGPhysicalBoxFragment* box_fragment = nullptr; wtf_size_t fragmentainer_idx = context.current_fragmentainer.fragmentainer_idx; + const ContainingFragment* oof_containing_fragment_info = nullptr; PhysicalOffset paint_offset; const auto* child_box = DynamicTo<LayoutBox>(child); bool is_first_for_node = true; @@ -919,20 +920,20 @@ // be the right place to search. const NGPhysicalBoxFragment* search_fragment = parent_fragment; if (child_box->IsOutOfFlowPositioned()) { - const ContainingFragment& containing_fragment_info = + oof_containing_fragment_info = child_box->IsFixedPositioned() - ? context.fixed_positioned_container - : context.absolute_positioned_container; + ? &context.fixed_positioned_container + : &context.absolute_positioned_container; if (context.current_fragmentainer.fragmentation_nesting_level != - containing_fragment_info.fragmentation_nesting_level) { + oof_containing_fragment_info->fragmentation_nesting_level) { // Only walk OOFs once if they aren't contained within the current // fragmentation context. if (!context.is_parent_first_for_node) continue; } - search_fragment = containing_fragment_info.fragment; - fragmentainer_idx = containing_fragment_info.fragmentainer_idx; + search_fragment = oof_containing_fragment_info->fragment; + fragmentainer_idx = oof_containing_fragment_info->fragmentainer_idx; } if (search_fragment) { @@ -958,7 +959,20 @@ NGPrePaintInfo pre_paint_info(*box_fragment, paint_offset, fragmentainer_idx, is_first_for_node, is_last_for_node, is_inside_fragment_child); - Walk(*child, context, &pre_paint_info); + if (oof_containing_fragment_info && + context.current_fragmentainer.fragmentation_nesting_level != + oof_containing_fragment_info->fragmentation_nesting_level) { + // We're walking an out-of-flow positioned descendant that isn't in the + // same fragmentation context as parent_object. Update the context, so + // that we create FragmentData objects correctly both for the descendant + // and all its descendants. + PrePaintTreeWalkContext oof_context( + context, NeedsTreeBuilderContextUpdate(*child, context)); + oof_context.current_fragmentainer = *oof_containing_fragment_info; + Walk(*child, oof_context, &pre_paint_info); + } else { + Walk(*child, context, &pre_paint_info); + } } else { Walk(*child, context, /* pre_paint_info */ nullptr); }
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 ddaf354..5b7a377c 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
@@ -15,6 +15,7 @@ #include "third_party/blink/public/web/web_hit_test_result.h" #include "third_party/blink/public/web/web_print_params.h" #include "third_party/blink/public/web/web_settings.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_intersection_observer_init.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/element.h" @@ -39,6 +40,7 @@ #include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h" +#include "third_party/blink/renderer/platform/graphics/logging_canvas.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" #include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h" #include "third_party/blink/renderer/platform/testing/find_cc_layer.h" @@ -46,8 +48,6 @@ #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" -#include "third_party/blink/renderer/platform/graphics/logging_canvas.h" - using testing::_; namespace blink { @@ -1276,7 +1276,8 @@ v8::Local<v8::Value> result = ClassicScript::CreateUnspecifiedScript("window.didRaf;") ->RunScriptAndReturnValue( - To<LocalDOMWindow>(frame_element->contentWindow())); + To<LocalDOMWindow>(frame_element->contentWindow())) + .GetSuccessValueOrEmpty(); EXPECT_TRUE(result->IsTrue()); }
diff --git a/third_party/blink/renderer/core/script/classic_script.cc b/third_party/blink/renderer/core/script/classic_script.cc index 711677b2..09c270a 100644 --- a/third_party/blink/renderer/core/script/classic_script.cc +++ b/third_party/blink/renderer/core/script/classic_script.cc
@@ -190,18 +190,14 @@ RunScriptAndReturnValue(window, policy); } -v8::Local<v8::Value> ClassicScript::RunScriptAndReturnValue( +ScriptEvaluationResult ClassicScript::RunScriptAndReturnValue( LocalDOMWindow* window, ExecuteScriptPolicy policy) { - ScriptEvaluationResult result = RunScriptOnScriptStateAndReturnValue( + return RunScriptOnScriptStateAndReturnValue( ToScriptStateForMainWorld(window->GetFrame()), policy); - - if (result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess) - return result.GetSuccessValue(); - return v8::Local<v8::Value>(); } -v8::Local<v8::Value> ClassicScript::RunScriptInIsolatedWorldAndReturnValue( +ScriptEvaluationResult ClassicScript::RunScriptInIsolatedWorldAndReturnValue( LocalDOMWindow* window, int32_t world_id) { DCHECK_GT(world_id, 0); @@ -215,12 +211,8 @@ *DOMWrapperWorld::EnsureIsolatedWorld( ToIsolate(window->GetFrame()), world_id)); } - ScriptEvaluationResult result = RunScriptOnScriptStateAndReturnValue( + return RunScriptOnScriptStateAndReturnValue( script_state, ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled); - - if (result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess) - return result.GetSuccessValue(); - return v8::Local<v8::Value>(); } bool ClassicScript::RunScriptOnWorkerOrWorklet(
diff --git a/third_party/blink/renderer/core/script/classic_script.h b/third_party/blink/renderer/core/script/classic_script.h index cb7fd80..9aec9af 100644 --- a/third_party/blink/renderer/core/script/classic_script.h +++ b/third_party/blink/renderer/core/script/classic_script.h
@@ -109,20 +109,19 @@ // Unlike RunScript() and RunScriptOnWorkerOrWorklet(), callers of the // following methods must enter a v8::HandleScope before calling. - // TODO(crbug.com/1129743): Use ScriptEvaluationResult instead of - // v8::Local<v8::Value> as the return type. ScriptEvaluationResult RunScriptOnScriptStateAndReturnValue( ScriptState*, ExecuteScriptPolicy = ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled, V8ScriptRunner::RethrowErrorsOption = V8ScriptRunner::RethrowErrorsOption::DoNotRethrow()); - v8::Local<v8::Value> RunScriptAndReturnValue( + ScriptEvaluationResult RunScriptAndReturnValue( LocalDOMWindow*, ExecuteScriptPolicy = ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled); - v8::Local<v8::Value> RunScriptInIsolatedWorldAndReturnValue(LocalDOMWindow*, - int32_t world_id); + ScriptEvaluationResult RunScriptInIsolatedWorldAndReturnValue( + LocalDOMWindow*, + int32_t world_id); private: mojom::blink::ScriptType GetScriptType() const override {
diff --git a/third_party/blink/renderer/core/script/module_script_test.cc b/third_party/blink/renderer/core/script/module_script_test.cc index 48ae257..b2460e4a 100644 --- a/third_party/blink/renderer/core/script/module_script_test.cc +++ b/third_party/blink/renderer/core/script/module_script_test.cc
@@ -8,6 +8,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h" @@ -106,7 +107,8 @@ static void TestFoo(V8TestingScope& scope) { v8::Local<v8::Value> value = ClassicScript::CreateUnspecifiedScript("window.foo") - ->RunScriptAndReturnValue(&scope.GetWindow()); + ->RunScriptAndReturnValue(&scope.GetWindow()) + .GetSuccessValueOrEmpty(); EXPECT_TRUE(value->IsNumber()); EXPECT_EQ(kScriptRepeatLength, value->NumberValue(scope.GetContext()).ToChecked());
diff --git a/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc b/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc index ab1deabb..2f9f191 100644 --- a/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc +++ b/third_party/blink/renderer/core/xml/document_xml_tree_viewer.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/xml/document_xml_tree_viewer.h" #include "third_party/blink/public/resources/grit/blink_resources.h" +#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/script/classic_script.h"
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 3573b96..497fc704 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
@@ -6,7 +6,6 @@ #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" @@ -171,8 +170,9 @@ GetPermissionService()->RequestPermission( CreatePermissionDescriptor(permission_name), LocalFrame::HasTransientUserActivation(local_frame), - WTF::Bind(&WakeLock::DidReceivePermissionResponse, WrapPersistent(this), - type, WrapPersistent(resolver))); + resolver->WrapCallbackInScriptScope( + WTF::Bind(&WakeLock::DidReceivePermissionResponse, + WrapPersistent(this), type))); } void WakeLock::DidReceivePermissionResponse(V8WakeLockType::Enum type, @@ -181,17 +181,6 @@ // https://w3c.github.io/screen-wake-lock/#the-request-method DCHECK(status == PermissionStatus::GRANTED || status == PermissionStatus::DENIED); - DCHECK(resolver); - // Support creating DOMException with JS stack. - ScriptState* resolver_script_state = resolver->GetScriptState(); - if (!IsInParallelAlgorithmRunnable(resolver->GetExecutionContext(), - resolver_script_state)) { - return; - } - // switch to the resolver's context to let DOMException pick up the resolver's - // JS stack - ScriptState::Scope script_state_scope(resolver_script_state); - // 8.2. If state is "denied", then: // 8.2.1. Queue a global task on the screen wake lock task source given // document's relevant global object to reject promise with a @@ -199,7 +188,8 @@ // 8.2.2. Abort these steps. if (status != PermissionStatus::GRANTED) { resolver->Reject(V8ThrowDOMException::CreateOrDie( - resolver_script_state->GetIsolate(), DOMExceptionCode::kNotAllowedError, + resolver->GetScriptState()->GetIsolate(), + DOMExceptionCode::kNotAllowedError, "Wake Lock permission request denied")); return; } @@ -212,7 +202,8 @@ // 8.3.1.1. Reject promise with a "NotAllowedError" DOMException. // 8.3.1.2. Abort these steps. resolver->Reject(V8ThrowDOMException::CreateOrDie( - resolver_script_state->GetIsolate(), DOMExceptionCode::kNotAllowedError, + resolver->GetScriptState()->GetIsolate(), + DOMExceptionCode::kNotAllowedError, "The requesting page is not visible")); return; }
diff --git a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc index 0a921ad2..b6eff793 100644 --- a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h" #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" #include "third_party/blink/renderer/platform/bindings/exception_messages.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.cc b/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.cc index 18027e1..715b46d 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_node.cc
@@ -28,6 +28,7 @@ #include <algorithm> #include "third_party/blink/public/platform/task_type.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" #include "third_party/blink/renderer/platform/audio/audio_utilities.h"
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h index 374629a..f6df421 100644 --- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h +++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -29,27 +29,20 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" -#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_decode_error_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.h" #include "third_party/blink/renderer/core/dom/events/event_listener.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h" -#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" -#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webaudio/async_audio_decoder.h" #include "third_party/blink/renderer/modules/webaudio/audio_destination_node.h" #include "third_party/blink/renderer/modules/webaudio/deferred_task_handler.h" -#include "third_party/blink/renderer/modules/webaudio/iir_filter_node.h" #include "third_party/blink/renderer/modules/webaudio/inspector_helper_mixin.h" -#include "third_party/blink/renderer/platform/audio/audio_bus.h" #include "third_party/blink/renderer/platform/audio/audio_callback_metric_reporter.h" #include "third_party/blink/renderer/platform/audio/audio_io_callback.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/prefinalizer.h" -#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/threading.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/modules/webaudio/iir_filter_handler.cc b/third_party/blink/renderer/modules/webaudio/iir_filter_handler.cc index db567f9..89ab9d19 100644 --- a/third_party/blink/renderer/modules/webaudio/iir_filter_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/iir_filter_handler.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" #include "third_party/blink/renderer/modules/webaudio/iir_processor.h"
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc index 9f18802..6f9e27fa 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
@@ -27,6 +27,7 @@ #include <algorithm> #include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_input.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h" #include "third_party/blink/renderer/modules/webaudio/audio_worklet.h"
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc index 330fd96..bc4c08b 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -1188,9 +1188,20 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageData(kTexImage2D, target, level, internalformat, 0, format, - type, 1, 0, 0, 0, pixels, - GetTextureSourceSubRectangle(width, height), 0); + TexImageParams params = { + .function_id = kTexImage2D, + .target = target, + .level = level, + .internalformat = internalformat, + .width = width, + .height = height, + .depth = 1, + .border = 0, // See https://crbug.com/1313604 + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageData(params, pixels); } void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context, @@ -1311,9 +1322,20 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageBitmap( - kTexImage2D, target, level, internalformat, format, type, 0, 0, 0, bitmap, - GetTextureSourceSubRectangle(width, height), 1, 0, exception_state); + TexImageParams params = { + .function_id = kTexImage2D, + .target = target, + .level = level, + .internalformat = internalformat, + .width = width, + .height = height, + .depth = 1, + .border = 0, // See https://crbug.com/1313604 + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageBitmap(params, bitmap, exception_state); } void WebGL2RenderingContextBase::texImage2D(GLenum target, @@ -1497,9 +1519,20 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageData(kTexSubImage2D, target, level, 0, 0, format, type, 1, - xoffset, yoffset, 0, pixels, - GetTextureSourceSubRectangle(width, height), 0); + TexImageParams params = { + .function_id = kTexSubImage2D, + .target = target, + .level = level, + .xoffset = xoffset, + .yoffset = yoffset, + .width = width, + .height = height, + .depth = 1, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageData(params, pixels); } void WebGL2RenderingContextBase::texSubImage2D( @@ -1625,10 +1658,20 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageBitmap(kTexSubImage2D, target, level, 0, format, type, - xoffset, yoffset, 0, bitmap, - GetTextureSourceSubRectangle(width, height), 1, 0, - exception_state); + TexImageParams params = { + .function_id = kTexSubImage2D, + .target = target, + .level = level, + .xoffset = xoffset, + .yoffset = yoffset, + .width = width, + .height = height, + .depth = 1, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageBitmap(params, bitmap, exception_state); } void WebGL2RenderingContextBase::texSubImage2D(GLenum target, @@ -1871,11 +1914,20 @@ GLenum type, ImageData* pixels) { DCHECK(pixels); - gfx::Rect source_image_rect(unpack_skip_pixels_, unpack_skip_rows_, width, - height); - TexImageHelperImageData(kTexImage3D, target, level, internalformat, 0, format, - type, depth, 0, 0, 0, pixels, source_image_rect, - unpack_image_height_); + TexImageParams params = { + .function_id = kTexImage3D, + .target = target, + .level = level, + .internalformat = internalformat, + .width = width, + .height = height, + .depth = depth, + .border = 0, // See https://crbug.com/1313604 + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageData(params, pixels); } void WebGL2RenderingContextBase::texImage3D(ExecutionContext* execution_context, @@ -2003,10 +2055,20 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageBitmap(kTexImage3D, target, level, internalformat, format, - type, 0, 0, 0, bitmap, - GetTextureSourceSubRectangle(width, height), depth, - unpack_image_height_, exception_state); + TexImageParams params = { + .function_id = kTexImage3D, + .target = target, + .level = level, + .internalformat = internalformat, + .width = width, + .height = height, + .depth = depth, + .border = 0, // See https://crbug.com/1313604 + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageBitmap(params, bitmap, exception_state); } void WebGL2RenderingContextBase::texSubImage3D( @@ -2099,10 +2161,21 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageData(kTexSubImage3D, target, level, 0, 0, format, type, - depth, xoffset, yoffset, zoffset, pixels, - GetTextureSourceSubRectangle(width, height), - unpack_image_height_); + TexImageParams params = { + .function_id = kTexSubImage3D, + .target = target, + .level = level, + .xoffset = xoffset, + .yoffset = yoffset, + .zoffset = zoffset, + .width = width, + .height = height, + .depth = depth, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageData(params, pixels); } void WebGL2RenderingContextBase::texSubImage3D( @@ -2241,10 +2314,21 @@ "a buffer is bound to PIXEL_UNPACK_BUFFER"); return; } - TexImageHelperImageBitmap(kTexSubImage3D, target, level, 0, format, type, - xoffset, yoffset, zoffset, bitmap, - GetTextureSourceSubRectangle(width, height), depth, - unpack_image_height_, exception_state); + TexImageParams params = { + .function_id = kTexSubImage3D, + .target = target, + .level = level, + .xoffset = xoffset, + .yoffset = yoffset, + .zoffset = zoffset, + .width = width, + .height = height, + .depth = depth, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageBitmap(params, bitmap, exception_state); } void WebGL2RenderingContextBase::copyTexSubImage3D(GLenum target,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 0a52988..5e83d81 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -5452,22 +5452,9 @@ 0, pixels.Get(), kNullAllowed, 0); } -void WebGLRenderingContextBase::TexImageHelperImageData( - TexImageFunctionID function_id, - GLenum target, - GLint level, - GLint internalformat, - GLint border, - GLenum format, - GLenum type, - GLsizei depth, - GLint xoffset, - GLint yoffset, - GLint zoffset, - ImageData* pixels, - const gfx::Rect& source_image_rect, - GLint unpack_image_height) { - const char* func_name = GetTexImageFunctionName(function_id); +void WebGLRenderingContextBase::TexImageHelperImageData(TexImageParams params, + ImageData* pixels) { + const char* func_name = GetTexImageFunctionName(params.function_id); if (isContextLost()) return; DCHECK(pixels); @@ -5478,99 +5465,28 @@ return; } - if (!ValidateTexImageBinding(func_name, function_id, target)) + if (!ValidateTexImageBinding(func_name, params.function_id, params.target)) return; TexImageFunctionType function_type; - if (function_id == kTexImage2D || function_id == kTexImage3D) + if (params.function_id == kTexImage2D || params.function_id == kTexImage3D) function_type = kTexImage; else function_type = kTexSubImage; - if (!ValidateTexFunc(func_name, function_type, kSourceImageData, target, - level, internalformat, pixels->width(), pixels->height(), - depth, border, format, type, xoffset, yoffset, zoffset)) + if (!params.width) + params.width = pixels->width(); + if (!params.height) + params.height = pixels->height(); + if (!params.depth) + params.depth = 1; + if (!ValidateTexFunc(func_name, function_type, kSourceImageData, + params.target, params.level, params.internalformat, + pixels->width(), pixels->height(), *params.depth, + params.border, params.format, params.type, + params.xoffset, params.yoffset, params.zoffset)) return; - bool selecting_sub_rectangle = false; - if (!ValidateTexImageSubRectangle( - func_name, function_id, pixels, source_image_rect, depth, - unpack_image_height, &selecting_sub_rectangle)) { - return; - } - // Adjust the source image rectangle if doing a y-flip. - gfx::Rect adjusted_source_image_rect = source_image_rect; - if (unpack_flip_y_) { - adjusted_source_image_rect.set_y(pixels->height() - - adjusted_source_image_rect.bottom()); - } - - Vector<uint8_t> data; - bool need_conversion = true; - - GLenum image_type; - WebGLImageConversion::DataFormat data_format; - switch (pixels->GetImageDataStorageFormat()) { - case ImageDataStorageFormat::kUint8: - image_type = GL_UNSIGNED_BYTE; - data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA8; - break; - case ImageDataStorageFormat::kUint16: - image_type = GL_UNSIGNED_SHORT; - data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA16; - break; - case ImageDataStorageFormat::kFloat32: - image_type = GL_FLOAT; - data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA32F; - break; - default: - NOTREACHED(); - } - - // No conversion is needed if destination format is RGBA and type is - // same as the source image type and no Flip or Premultiply operation is - // required. - if (!unpack_flip_y_ && !unpack_premultiply_alpha_ && format == GL_RGBA && - type == image_type && !selecting_sub_rectangle && depth == 1 && - data_format == format) { - need_conversion = false; - } else { - if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) { - // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented. - type = GL_FLOAT; - } - if (!WebGLImageConversion::ExtractImageData( - pixels->GetSkPixmap().writable_addr(), data_format, pixels->Size(), - adjusted_source_image_rect, depth, unpack_image_height, format, - type, unpack_flip_y_, unpack_premultiply_alpha_, data)) { - SynthesizeGLError(GL_INVALID_VALUE, func_name, "bad image data"); - return; - } - } - ScopedUnpackParametersResetRestore temporary_reset_unpack(this); - const void* bytes = - need_conversion ? data.data() : pixels->GetSkPixmap().writable_addr(); - if (function_id == kTexImage2D) { - DCHECK_EQ(unpack_image_height, 0); - TexImage2DBase( - target, level, internalformat, adjusted_source_image_rect.width(), - adjusted_source_image_rect.height(), border, format, type, bytes); - } else if (function_id == kTexSubImage2D) { - DCHECK_EQ(unpack_image_height, 0); - ContextGL()->TexSubImage2D( - target, level, xoffset, yoffset, adjusted_source_image_rect.width(), - adjusted_source_image_rect.height(), format, type, bytes); - } else { - GLint upload_height = adjusted_source_image_rect.height(); - if (function_id == kTexImage3D) { - ContextGL()->TexImage3D(target, level, internalformat, - adjusted_source_image_rect.width(), upload_height, - depth, border, format, type, bytes); - } else { - DCHECK_EQ(function_id, kTexSubImage3D); - ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, - adjusted_source_image_rect.width(), - upload_height, depth, format, type, bytes); - } - } + auto pixmap = pixels->GetSkPixmap(); + TexImageSkPixmap(params, &pixmap, /*pixmap_has_flip_y=*/false); } void WebGLRenderingContextBase::texImage2D(GLenum target, @@ -5579,9 +5495,16 @@ GLenum format, GLenum type, ImageData* pixels) { - TexImageHelperImageData(kTexImage2D, target, level, internalformat, 0, format, - type, 1, 0, 0, 0, pixels, GetImageDataSize(pixels), - 0); + TexImageParams params = { + .function_id = kTexImage2D, + .target = target, + .level = level, + .internalformat = internalformat, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageData(params, pixels); } void WebGLRenderingContextBase::TexImageHelperHTMLImageElement( @@ -6335,21 +6258,10 @@ } void WebGLRenderingContextBase::TexImageHelperImageBitmap( - TexImageFunctionID function_id, - GLenum target, - GLint level, - GLint internalformat, - GLenum format, - GLenum type, - GLint xoffset, - GLint yoffset, - GLint zoffset, + TexImageParams params, ImageBitmap* bitmap, - const gfx::Rect& source_sub_rect, - GLsizei depth, - GLint unpack_image_height, ExceptionState& exception_state) { - const char* func_name = GetTexImageFunctionName(function_id); + const char* func_name = GetTexImageFunctionName(params.function_id); if (isContextLost()) return; @@ -6359,28 +6271,36 @@ if (!ValidateImageBitmap(func_name, bitmap, exception_state)) return; WebGLTexture* texture = - ValidateTexImageBinding(func_name, function_id, target); + ValidateTexImageBinding(func_name, params.function_id, params.target); if (!texture) return; + if (!params.width) + params.width = bitmap->width(); + if (!params.height) + params.height = bitmap->height(); + if (!params.depth) + params.depth = 1; + const gfx::Rect source_sub_rect(params.unpack_skip_pixels, + params.unpack_skip_rows, *params.width, + *params.height); bool selecting_sub_rectangle = false; - if (!ValidateTexImageSubRectangle(func_name, function_id, bitmap, - source_sub_rect, depth, unpack_image_height, - &selecting_sub_rectangle)) { + if (!ValidateTexImageSubRectangle( + func_name, params.function_id, bitmap, source_sub_rect, *params.depth, + params.unpack_image_height, &selecting_sub_rectangle)) { return; } TexImageFunctionType function_type; - if (function_id == kTexImage2D) + if (params.function_id == kTexImage2D) function_type = kTexImage; else function_type = kTexSubImage; - - GLsizei width = source_sub_rect.width(); - GLsizei height = source_sub_rect.height(); - if (!ValidateTexFunc(func_name, function_type, kSourceImageBitmap, target, - level, internalformat, width, height, depth, 0, format, - type, xoffset, yoffset, zoffset)) + if (!ValidateTexFunc(func_name, function_type, kSourceImageBitmap, + params.target, params.level, params.internalformat, + *params.width, *params.height, *params.depth, 0, + params.format, params.type, params.xoffset, + params.yoffset, params.zoffset)) return; scoped_refptr<StaticBitmapImage> image = bitmap->BitmapImage(); @@ -6405,8 +6325,9 @@ } // TODO(kbr): make this work for sub-rectangles of ImageBitmaps. - if (function_id != kTexSubImage3D && function_id != kTexImage3D && - image->IsTextureBacked() && CanUseTexImageViaGPU(format, type) && + if (params.function_id != kTexSubImage3D && + params.function_id != kTexImage3D && image->IsTextureBacked() && + CanUseTexImageViaGPU(params.format, params.type) && !selecting_sub_rectangle) { AcceleratedStaticBitmapImage* accel_image = static_cast<AcceleratedStaticBitmapImage*>(image.get()); @@ -6414,15 +6335,17 @@ // have already been manipulated during construction of the ImageBitmap. bool premultiply_alpha = true; // TODO(kbr): this looks wrong! bool flip_y = false; - if (function_id == kTexImage2D) { - TexImage2DBase(target, level, internalformat, width, height, 0, format, - type, nullptr); - TexImageViaGPU(function_id, texture, target, level, 0, 0, 0, accel_image, - nullptr, source_sub_rect, premultiply_alpha, flip_y); - } else if (function_id == kTexSubImage2D) { - TexImageViaGPU(function_id, texture, target, level, xoffset, yoffset, 0, - accel_image, nullptr, source_sub_rect, premultiply_alpha, - flip_y); + if (params.function_id == kTexImage2D) { + TexImage2DBase(params.target, params.level, params.internalformat, + *params.width, *params.height, 0, params.format, + params.type, nullptr); + TexImageViaGPU(params.function_id, texture, params.target, params.level, + 0, 0, 0, accel_image, nullptr, source_sub_rect, + premultiply_alpha, flip_y); + } else if (params.function_id == kTexSubImage2D) { + TexImageViaGPU(params.function_id, texture, params.target, params.level, + params.xoffset, params.yoffset, 0, accel_image, nullptr, + source_sub_rect, premultiply_alpha, flip_y); } return; } @@ -6444,84 +6367,29 @@ } SkPixmap pixmap; - uint8_t* pixel_data_ptr = nullptr; Vector<uint8_t> pixel_data; // PaintImage::GetSwSkImage() can return a lazily generated image which will // cause peekPixels() to fail. In that case we use CopyBitmapData to force // image generation. - bool peek_succeed = sk_image->peekPixels(&pixmap); - if (peek_succeed) { - pixel_data_ptr = static_cast<uint8_t*>(pixmap.writable_addr()); - } else { + if (!sk_image->peekPixels(&pixmap)) { SkImageInfo info = bitmap->GetBitmapSkImageInfo(); info = info.makeAlphaType(image->IsPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); if (info.colorType() == kN32_SkColorType) info = info.makeColorType(kRGBA_8888_SkColorType); pixel_data = image->CopyImageData(info, /*apply_orientation=*/true); - pixel_data_ptr = pixel_data.data(); + pixmap = SkPixmap(info, pixel_data.data(), info.minRowBytes()); } - Vector<uint8_t> data; - bool need_conversion = true; - bool have_peekable_rgba = - (peek_succeed && - pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType); - bool is_pixel_data_rgba = (have_peekable_rgba || !peek_succeed); - if (is_pixel_data_rgba && format == GL_RGBA && type == GL_UNSIGNED_BYTE && - !selecting_sub_rectangle && depth == 1) { - need_conversion = false; - } else { - if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) { - // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented. - type = GL_FLOAT; - } - WebGLImageConversion::DataFormat data_format; - if (is_pixel_data_rgba) { - data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA8; - } else { - switch (pixmap.colorType()) { - case SkColorType::kBGRA_8888_SkColorType: - data_format = WebGLImageConversion::DataFormat::kDataFormatBGRA8; - break; - case SkColorType::kRGBA_F16_SkColorType: - // Used in ImageBitmap's ApplyColorSpaceConversion. - data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA16F; - break; - default: - // Can not handle this ImageBitmap's format. - SynthesizeGLError(GL_INVALID_VALUE, func_name, - "unsupported color type / space in ImageBitmap"); - return; - } - } - // In the case of ImageBitmap, we do not need to apply flipY or - // premultiplyAlpha. - if (!WebGLImageConversion::ExtractImageData( - pixel_data_ptr, data_format, bitmap->Size(), source_sub_rect, depth, - unpack_image_height, format, type, false, false, data)) { - SynthesizeGLError(GL_INVALID_VALUE, func_name, - "error extracting data from ImageBitmap"); - return; - } - } - ScopedUnpackParametersResetRestore temporary_reset_unpack(this); - if (function_id == kTexImage2D) { - TexImage2DBase(target, level, internalformat, width, height, 0, format, - type, need_conversion ? data.data() : pixel_data_ptr); - } else if (function_id == kTexSubImage2D) { - ContextGL()->TexSubImage2D(target, level, xoffset, yoffset, width, height, - format, type, - need_conversion ? data.data() : pixel_data_ptr); - } else if (function_id == kTexImage3D) { - ContextGL()->TexImage3D(target, level, internalformat, width, height, depth, - 0, format, type, - need_conversion ? data.data() : pixel_data_ptr); - } else { - DCHECK_EQ(function_id, kTexSubImage3D); - ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, - height, depth, format, type, - need_conversion ? data.data() : pixel_data_ptr); - } + + // When TexImage is called with an ImageBitmap, the values of UNPACK_FLIP_Y, + // UNPACK_PREMULTIPLY_ALPHA, and UNPACK_COLORSPACE_CONVERSION are to be + // ignored. Set `adjusted_params` such that no conversions will be made using + // that state. + TexImageParams adjusted_params = params; + adjusted_params.unpack_premultiply_alpha = + pixmap.alphaType() == kPremul_SkAlphaType; + adjusted_params.unpack_flip_y = false; + TexImageSkPixmap(adjusted_params, &pixmap, /*pixmap_has_flip_y=*/false); } void WebGLRenderingContextBase::texImage2D(GLenum target, @@ -6531,9 +6399,16 @@ GLenum type, ImageBitmap* bitmap, ExceptionState& exception_state) { - TexImageHelperImageBitmap(kTexImage2D, target, level, internalformat, format, - type, 0, 0, 0, bitmap, GetTextureSourceSize(bitmap), - 1, 0, exception_state); + TexImageParams params = { + .function_id = kTexImage2D, + .target = target, + .level = level, + .internalformat = internalformat, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageBitmap(params, bitmap, exception_state); } void WebGLRenderingContextBase::TexParameter(GLenum target, @@ -6650,9 +6525,17 @@ GLenum format, GLenum type, ImageData* pixels) { - TexImageHelperImageData(kTexSubImage2D, target, level, 0, 0, format, type, 1, - xoffset, yoffset, 0, pixels, GetImageDataSize(pixels), - 0); + TexImageParams params = { + .function_id = kTexSubImage2D, + .target = target, + .level = level, + .xoffset = xoffset, + .yoffset = yoffset, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageData(params, pixels); } void WebGLRenderingContextBase::texSubImage2D( @@ -6727,9 +6610,17 @@ GLenum type, ImageBitmap* bitmap, ExceptionState& exception_state) { - TexImageHelperImageBitmap( - kTexSubImage2D, target, level, 0, format, type, xoffset, yoffset, 0, - bitmap, GetTextureSourceSize(bitmap), 1, 0, exception_state); + TexImageParams params = { + .function_id = kTexSubImage2D, + .target = target, + .level = level, + .xoffset = xoffset, + .yoffset = yoffset, + .format = format, + .type = type, + }; + GetCurrentUnpackState(params); + TexImageHelperImageBitmap(params, bitmap, exception_state); } void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h index a0e5c18..4558aaef 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -1792,20 +1792,7 @@ DOMArrayBufferView*, NullDisposition, GLuint src_offset); - void TexImageHelperImageData(TexImageFunctionID, - GLenum, - GLint, - GLint, - GLint, - GLenum, - GLenum, - GLsizei, - GLint, - GLint, - GLint, - ImageData*, - const gfx::Rect&, - GLint); + void TexImageHelperImageData(TexImageParams, ImageData*); void TexImageHelperHTMLImageElement(const SecurityOrigin*, TexImageFunctionID, @@ -1871,19 +1858,8 @@ GLint, ExceptionState&); - void TexImageHelperImageBitmap(TexImageFunctionID, - GLenum, - GLint, - GLint, - GLenum, - GLenum, - GLint, - GLint, - GLint, + void TexImageHelperImageBitmap(TexImageParams params, ImageBitmap*, - const gfx::Rect&, - GLsizei, - GLint, ExceptionState&); static const char* GetTexImageFunctionName(TexImageFunctionID); gfx::Rect SafeGetImageSize(Image*);
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 86258b4..7434844 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3328,6 +3328,10 @@ crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 [ Mac10.12 ] external/wpt/content-security-policy/inheritance/history-iframe.sub.html [ Timeout ] +crbug.com/626703 [ Mac10.12 ] virtual/fenced-frame-shadow-dom/wpt_internal/fenced_frame/unfenced-top.https.html [ Timeout ] +crbug.com/626703 [ Mac10.12 ] virtual/portals/external/wpt/portals/history/history-manipulation-inside-portal.html [ Timeout ] +crbug.com/626703 [ Mac10.12 ] virtual/v8-off-thread-finalization/external/wpt/html/semantics/scripting-1/the-script-element/script-text-modifications.html [ Timeout ] crbug.com/626703 external/wpt/css/css-contain/content-visibility/content-visibility-canvas.html [ Failure ] crbug.com/626703 external/wpt/css/css-contain/content-visibility/content-visibility-video.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/html/canvas/element/drawing-text-to-the-canvas/direction-inherit-rtl.html [ Failure ] @@ -6704,7 +6708,6 @@ crbug.com/1218714 [ Win ] virtual/scroll-unification/fast/forms/select-popup/popup-menu-scrollbar-button-scrolls.html [ Pass Timeout ] # Green Mac11 Test -crbug.com/1201406 [ Mac11 ] fast/events/touch/gesture/touch-gesture-scroll-listbox.html [ Failure ] crbug.com/1201406 [ Mac11 ] http/tests/credentialmanagement/credentialscontainer-create-from-nested-frame.html [ Crash Timeout ] crbug.com/1201406 [ Mac11 ] http/tests/credentialmanagement/credentialscontainer-create-origins.html [ Crash Timeout ] crbug.com/1201406 http/tests/credentialmanagement/publickeycredential-same-origin-with-ancestors.html [ Crash Pass Timeout ] @@ -7741,3 +7744,4 @@ # Sheriff 2022-04-06 crbug.com/1290670 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Failure Pass ] crbug.com/1313894 [ Mac10.14 ] rootscroller/root-scroller-paint-order.html [ Failure Pass ] +crbug.com/1314130 [ Mac ] fast/events/touch/gesture/touch-gesture-scroll-listbox.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index 2055cf8..ba027e8 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: 570accebfaee1dc159f6e0e774f75db899e85bac +Version: fe3c6d583713c0da55254088217bb823c8e2c9d5
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 9b9d319..5fa4811 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -1624,6 +1624,13 @@ {} ] ], + "relpos-inline-with-abspos-multicol-gets-block-child.html": [ + "19a9bdde3afbe96b3e5d62d41a93bc750cdab1d7", + [ + null, + {} + ] + ], "remove-spanner-after-spanner-in-inline-before-inline.html": [ "0836ef1a91ef921194209a6a4642b67d90a02b3a", [ @@ -13690,7 +13697,7 @@ }, "payment-handler": { "change-payment-method-manual.https.html": [ - "abdb3d711180b4440ba52d02559f221bdd5c30c1", + "1640420c625cdd544ed92d6815ea6dcc1cd8b980", [ null, {} @@ -13704,21 +13711,21 @@ ] ], "change-shipping-option-manual.https.html": [ - "00d1aee70b991924fde8562dffc5691567d676fb", + "2511fc5ea05152392d9257cacc07d1bc081f3fb6", [ null, {} ] ], "payment-request-event-manual.https.html": [ - "3c8deb3b92fe00d7b4bdf1c57f1e33ab553acee3", + "e595dd2160ff2bd4cb0701cb0786cf81385f4e75", [ null, {} ] ], "supports-shipping-contact-delegation-manual.https.html": [ - "75b3668981c900ecced0b1ffdd40a95f15125003", + "939e5429262b039eef36029ada3033652b35daf5", [ null, {} @@ -246162,6 +246169,10 @@ "9aef19cb73fa10c2962c489f43a4517e7f215116", [] ], + "__init__.py": [ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + [] + ], "arrays.js": [ "2b31bb4179c26d790174214be097160cc302d07c", [] @@ -246285,6 +246296,10 @@ "f957541f75ecc37416895d6bc19d1c229c0f71b8", [] ], + "__init__.py": [ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + [] + ], "resources": { "common.sub.js": [ "d0f88f170107b30d10a151b1e94eb2126a546bf5", @@ -246296,6 +246311,10 @@ ] }, "scope": { + "__init__.py": [ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + [] + ], "document.py": [ "9a9f045e640fd57f66031b59cd9d21da8a55bfe7", [] @@ -248900,6 +248919,10 @@ "ed86aebf1837646e2808619e446d03bfe5b86000", [] ], + "__init__.py": [ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + [] + ], "attributes": { "resources": { "domain-child.sub.html": [ @@ -249009,6 +249032,10 @@ } }, "resources": { + "__init__.py": [ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + [] + ], "cookie-helper.sub.js": [ "1420779e0d5a13d8da9a242324143e2e6b043afa", [] @@ -294599,7 +294626,7 @@ ], "python-handlers": { "index.md": [ - "53fa8009c2177f55172358d0474a4b0d26467db8", + "e52e137179277ab775770f564860859eeb80ccad", [] ] }, @@ -323279,7 +323306,7 @@ [] ], "app-can-make-payment.js": [ - "0bb949047359c004359b7f030f6d5d12a6015f9b", + "14fea9ce224af7b2688b096043bc12a194e27ebf", [] ], "app-change-payment-method.js": [ @@ -323294,28 +323321,24 @@ "ac3307b619ccfb464a5fa44820cea39befdd8f2e", [] ], + "app-simple.js": [ + "833a01f47e0c09ea306ebde565e72d2d2ed715e4", + [] + ], "app-supports-shipping-contact-delegation.js": [ "770e2de64f13eeef8a1ee21783c2997facc8ff0b", [] ], - "basic-card.js": [ - "2db5d4b719fac4dbcfa65f4166c16a5b8d253097", - [] - ], - "basic-card.json": [ - "002dd875849a96b20acfaa774018dbda28618d99", - [] - ], "can-make-payment-event-constructor.https.serviceworker.js": [ "01ce642d2342accaeadbbdc1f2f022dabd7a9689", [] ], "can-make-payment-event.https-expected.txt": [ - "37e87e92572553eced19c11086d43180b6d66ef7", + "032a53a666a897b91c9fbf8947ead811a13b9093", [] ], "can-make-payment-event.https.html.ini": [ - "24fa92557186663f052a346139dcb87db3e90767", + "dcbbfd605af4cddbbc76d35c30b27748e3189fcf", [] ], "change-payment-method-manual.https-expected.txt": [ @@ -323381,7 +323404,7 @@ [] ], "untrusted-event.js": [ - "240702956e449e9167320443aeb181ceaf70d38b", + "e067952cc3b7dd0eb74909001e49615e20a8f8b9", [] ] }, @@ -402828,12 +402851,10 @@ ] ], "input-pseudo-classes-in-has.html": [ - "620e7801cc36b1d6086264c62e4e755b31409c43", + "1c80327f6921a0a68815e2405908072a420d7f92", [ null, - { - "testdriver": true - } + {} ] ], "insert-sibling-001.html": [ @@ -498797,7 +498818,7 @@ ] ], "can-make-payment-event.https.html": [ - "c4e5453d953bd5304382c800e4d881bc99a1d9d1", + "b2016a05ec34fd8148a1b43a102ca3f1b51b6526", [ null, {} @@ -498919,7 +498940,7 @@ ] ], "payment-instruments.https.html": [ - "605d33122229206b8f63b3a4e04a08b16c015f35", + "121c131568852eafe1b9ce5f9ec148c2cbee3fb6", [ null, {} @@ -498947,7 +498968,7 @@ ] ], "same-object-attributes.https.html": [ - "b9a9dd82d247a80b00e4bc033eeea134d5f900c1", + "2e5dea3a4aed33378f25b09b6e58929e22f2f72c", [ null, {} @@ -584547,6 +584568,27 @@ {} ] ], + "nested-fixedpos-in-inline-crash-000.html": [ + "8d1d395e35c8a40faf07d688e6e51d34bc35e88f", + [ + null, + {} + ] + ], + "nested-fixedpos-in-inline-crash-001.html": [ + "dc4e8fba67f2c5a801b529747def70946d723ede", + [ + null, + {} + ] + ], + "nested-fixedpos-in-inline-crash-002.html": [ + "15a5a9633264d15709acdc48948c2d69c2c3cc31", + [ + null, + {} + ] + ], "nested-multicol-with-spanner-and-oof-crash-001.html": [ "88b902af50283f87439e73fde9564cbb2bcba73a", [
diff --git a/third_party/blink/web_tests/external/wpt/common/__init__.py b/third_party/blink/web_tests/external/wpt/common/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/common/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/__init__.py b/third_party/blink/web_tests/external/wpt/common/security-features/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/common/security-features/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/scope/__init__.py b/third_party/blink/web_tests/external/wpt/common/security-features/scope/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/common/security-features/scope/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/cookies/__init__.py b/third_party/blink/web_tests/external/wpt/cookies/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/cookies/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/cookies/resources/__init__.py b/third_party/blink/web_tests/external/wpt/cookies/resources/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/cookies/resources/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/nested-with-fragmented-oof-negative-top-offset.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/nested-with-fragmented-oof-negative-top-offset.html new file mode 100644 index 0000000..38f6288 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/nested-with-fragmented-oof-negative-top-offset.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1311398"> +<div style="columns:2; column-fill:auto; height:100px;"> + <div style="height:101px;"></div> + <div style="position:relative;"> + <div style="columns:2; column-fill:auto;"> + <div style="position:absolute; top:-50px;"> + <div style="height:100px;"></div> + </div> + </div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/input-pseudo-classes-in-has.html b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/input-pseudo-classes-in-has.html index 620e7801..1c80327 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/input-pseudo-classes-in-has.html +++ b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/input-pseudo-classes-in-has.html
@@ -5,9 +5,6 @@ <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-actions.js"></script> -<script src="/resources/testdriver-vendor.js"></script> <style> .ancestor:has(#checkme:checked) { color: green } .ancestor:has(#checkme:indeterminate) { color: yellowgreen } @@ -27,7 +24,10 @@ <input id="numberinput" type="number" min="1" max="10" value="5"> </div> <script> - test(() => { + test(function() { + this.add_cleanup(() => { + checkme.checked = false; + }); checkme.checked = false; assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", "ancestor should be black"); @@ -37,51 +37,92 @@ checkme.indeterminate = true; assert_equals(getComputedStyle(subject).color, "rgb(154, 205, 50)", "ancestor should be yellowgreen"); + const input = checkme; checkme.remove(); + input.indeterminate = false; assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", "ancestor should be black"); - { - const input = document.createElement('input'); - input.id = 'checkme'; - input.setAttribute('type', 'checkbox'); - input.setAttribute('name', 'my-checkbox'); - input.checked = true; - assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", - "ancestor should be black"); - subject.prepend(input); - assert_equals(getComputedStyle(subject).color, "rgb(0, 128, 0)", - "ancestor should be green"); - } + subject.prepend(input); + checkme.checked = true; + assert_equals(getComputedStyle(subject).color, "rgb(0, 128, 0)", + "ancestor should be green"); + }, ":checked & :indeterminate invalidation"); + test(function() { + this.add_cleanup(() => { + checkme.disabled = false; + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); checkme.disabled = true; assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 255)", "ancestor should be blue"); + }, ":disabled invalidation"); + test(function() { + this.add_cleanup(() => { + textinput.readOnly = false; + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); textinput.readOnly = true; assert_equals(getComputedStyle(subject).color, "rgb(135, 206, 235)", "ancestor should be skyblue"); - textinput.readOnly = false; + }, ":read-only invalidation"); - textinput.placeholder = 'placeholder text'; - assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 128)", - "ancestor should be navy"); - - radioinput.type = 'radio'; - assert_equals(getComputedStyle(subject).color, "rgb(173, 216, 230)", - "ancestor should be lightblue"); - + test(function() { + this.add_cleanup(() => { + textinput.value = ""; + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); textinput.value = "text input"; assert_equals(getComputedStyle(subject).color, "rgb(144, 238, 144)", "ancestor should be lightgreen"); + }, ":valid invalidation"); - numberinput.value = 12; - assert_equals(getComputedStyle(subject).color, "rgb(0, 100, 0)", - "ancestor should be darkgreen"); + test(function() { + this.add_cleanup(() => { + radioinput.removeAttribute("type"); + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); + radioinput.type = 'radio'; + assert_equals(getComputedStyle(subject).color, "rgb(173, 216, 230)", + "ancestor should be lightblue"); + }, ":default invalidation with input[type=radio]"); + test(function() { + this.add_cleanup(() => { + numberinput.required = false; + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); numberinput.required = true; assert_equals(getComputedStyle(subject).color, "rgb(255, 192, 203)", "ancestor should be pink"); + }, ":required invalidation"); - }); -</script> \ No newline at end of file + test(function() { + this.add_cleanup(() => { + numberinput.value = 5; + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); + numberinput.value = 12; + assert_equals(getComputedStyle(subject).color, "rgb(0, 100, 0)", + "ancestor should be darkgreen"); + }, ":out-of-range invalidation"); + + test(function() { + this.add_cleanup(() => { + textinput.removeAttribute("placeholder"); + }); + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 0)", + "ancestor should be black"); + textinput.placeholder = 'placeholder text'; + assert_equals(getComputedStyle(subject).color, "rgb(0, 0, 128)", + "ancestor should be navy"); + }, ":placeholder-shown invalidation"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md index 53fa800..e52e137 100644 --- a/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md +++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md
@@ -67,6 +67,17 @@ myhelper = importlib.import_module('common.security-features.myhelper') ``` +**Note on __init__ files**: Importing helper scripts like this +requires a 'path' of empty `__init__.py` files in every directory down +to the helper. For example, if your helper is +`css/css-align/resources/myhelper.py`, you need to have: + +``` +css/__init__.py +css/css-align/__init__.py +css/css-align/resources/__init__.py +``` + ## Example: Dynamic HTTP headers The following code defines a Python handler that allows the requester to
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/generate-test-wbns.sh b/third_party/blink/web_tests/external/wpt/web-bundle/resources/generate-test-wbns.sh index 529b3cc..be85434 100755 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/generate-test-wbns.sh +++ b/third_party/blink/web_tests/external/wpt/web-bundle/resources/generate-test-wbns.sh
@@ -15,47 +15,12 @@ wpt_test_remote_origin=https://www1.web-platform.test:8444 gen-bundle \ - -version b1 \ - -baseURL $wpt_test_origin/web-bundle/resources/wbn/ \ - -primaryURL $wpt_test_origin/web-bundle/resources/wbn/location.html \ - -dir location/ \ - -o wbn/location-b1.wbn - -gen-bundle \ -version b2 \ -baseURL $wpt_test_origin/web-bundle/resources/wbn/static-element/ \ -primaryURL $wpt_test_origin/web-bundle/resources/wbn/static-element/resources/style.css \ -dir static-element/ \ -o wbn/static-element.wbn -gen-bundle \ - -version b1 \ - -baseURL $wpt_test_origin/web-bundle/resources/wbn/dynamic/ \ - -primaryURL $wpt_test_origin/web-bundle/resources/wbn/dynamic/resource1.js \ - -dir dynamic1/ \ - -o wbn/dynamic1-b1.wbn - -gen-bundle \ - -version b1 \ - -baseURL $wpt_test_origin/web-bundle/resources/wbn/dynamic/ \ - -primaryURL $wpt_test_origin/web-bundle/resources/wbn/dynamic/resource1.js \ - -dir dynamic2/ \ - -o wbn/dynamic2-b1.wbn - -gen-bundle \ - -version b1 \ - -baseURL $wpt_test_remote_origin/web-bundle/resources/wbn/dynamic/ \ - -primaryURL $wpt_test_remote_origin/web-bundle/resources/wbn/dynamic/resource1.js \ - -dir dynamic1/ \ - -o wbn/dynamic1-crossorigin-b1.wbn - -gen-bundle \ - -version b1 \ - -baseURL $wpt_test_origin/web-bundle/resources/ \ - -primaryURL $wpt_test_origin/web-bundle/resources/wbn/resource.js \ - -dir path-restriction/ \ - -o wbn/path-restriction-b1.wbn - # Create a bundle, nested-main.wbn, which includes nested-sub.wbn. cp -a wbn/subresource.wbn nested/nested-sub.wbn gen-bundle \ @@ -66,18 +31,6 @@ -o wbn/nested-main.wbn gen-bundle \ - -version b1 \ - -har cross-origin.har \ - -primaryURL $wpt_test_remote_origin/web-bundle/resources/wbn/cors/resource.cors.js \ - -o wbn/cors/cross-origin-b1.wbn - -gen-bundle \ - -version b1 \ - -har cross-origin-no-cors.har \ - -primaryURL $wpt_test_remote_origin/web-bundle/resources/wbn/no-cors/resource.cors.js \ - -o wbn/no-cors/cross-origin-b1.wbn - -gen-bundle \ -version b2 \ -har non-utf8-query-encoding.har \ -primaryURL $wpt_test_origin/web-bundle/resources/wbn/static-element/resources/script.js?x=%A4%A2 \
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/cors/cross-origin-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/cors/cross-origin-b1.wbn deleted file mode 100644 index 942ddb6..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/cors/cross-origin-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic1-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic1-b1.wbn deleted file mode 100644 index 943e00e6..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic1-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic1-crossorigin-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic1-crossorigin-b1.wbn deleted file mode 100644 index 4d2d42d..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic1-crossorigin-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic2-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic2-b1.wbn deleted file mode 100644 index 0d9a6e743..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/dynamic2-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/location-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/location-b1.wbn deleted file mode 100644 index a566446..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/location-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/no-cors/cross-origin-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/no-cors/cross-origin-b1.wbn deleted file mode 100644 index 4ceb691..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/no-cors/cross-origin-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/path-restriction-b1.wbn b/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/path-restriction-b1.wbn deleted file mode 100644 index e031084..0000000 --- a/third_party/blink/web_tests/external/wpt/web-bundle/resources/wbn/path-restriction-b1.wbn +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/script-subresource-load.https.tentative.sub.html b/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/script-subresource-load.https.tentative.sub.html index b00ff11..10c2070 100644 --- a/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/script-subresource-load.https.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/script-subresource-load.https.tentative.sub.html
@@ -44,53 +44,6 @@ }, "Subresource loading with WebBundle shouldn't affect redirect"); promise_test(async () => { - const element = createWebBundleElement( - "../resources/wbn/dynamic1-b1.wbn", - [ - "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource1.js", - "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource2.js", - "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource4.js", - ] - ); - document.body.appendChild(element); - - const module = await import( - "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource1.js" - ); - assert_equals(module.result, "resource1 from dynamic1.wbn"); - document.body.removeChild(element); - }, "Subresource loading from a b1 bundle"); - - promise_test(async () => { - const classic_script_url = - "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/classic_script.js"; - const element = createWebBundleElement( - "../resources/wbn/dynamic1-b1.wbn", - [classic_script_url] - ); - document.body.appendChild(element); - assert_equals( - await loadScriptAndWaitReport(classic_script_url), - "classic script from dynamic1.wbn" - ); - const new_element = removeAndAppendNewElementWithUpdatedRule(element, { - url: "../resources/wbn/dynamic2-b1.wbn", - }); - // Loading the classic script should not reuse the previously loaded - // script. So in this case, the script must be loaded from dynamic2-b1.wbn. - assert_equals( - await loadScriptAndWaitReport(classic_script_url), - "classic script from dynamic2.wbn" - ); - document.body.removeChild(new_element); - // And in this case, the script must be loaded from network. - assert_equals( - await loadScriptAndWaitReport(classic_script_url), - "classic script from network" - ); - }, "Dynamically loading classic script from a 'b1' web bundle with resources attribute"); - - promise_test(async () => { const element = createWebBundleElement("../resources/wbn/dynamic1.wbn", [ "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource1.js", "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource2.js", @@ -104,7 +57,7 @@ assert_equals(module.result, "resource1 from dynamic1.wbn"); const new_element = removeAndAppendNewElementWithUpdatedRule(element, { - url: "../resources/wbn/dynamic2-b1.wbn", + url: "../resources/wbn/dynamic2.wbn", }); const module2 = await import( "https://{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource2.js" @@ -144,7 +97,7 @@ "classic script from dynamic1.wbn" ); const new_element = removeAndAppendNewElementWithUpdatedRule(element, { - url: "../resources/wbn/dynamic2-b1.wbn", + url: "../resources/wbn/dynamic2.wbn", }); // Loading the classic script should not reuse the previously loaded // script. So in this case, the script must be loaded from dynamic2.wbn. @@ -294,18 +247,6 @@ }, "Subresource URL must be same-origin with bundle URL"); promise_test(async () => { - const module_script_url = - "https://www1.{{domains[]}}:{{ports[https][0]}}/web-bundle/resources/wbn/dynamic/resource1.js"; - const element = createWebBundleElement( - "../resources/wbn/dynamic1-crossorigin-b1.wbn", - [module_script_url] - ); - document.body.appendChild(element); - const module = await import(module_script_url); - assert_equals(module.result, "resource1 from network"); - }, "Subresource URL must be same-origin with bundle URL (for 'b1' bundles too)"); - - promise_test(async () => { const url = "uuid-in-package:020111b3-437a-4c5c-ae07-adb6bbffb720"; const element = createWebBundleElement( "../resources/wbn/uuid-in-package.wbn",
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/wbn-from-network/wbn-location.tentative.html b/third_party/blink/web_tests/external/wpt/web-bundle/wbn-from-network/wbn-location.tentative.html index e774a82..20b554b4 100644 --- a/third_party/blink/web_tests/external/wpt/web-bundle/wbn-from-network/wbn-location.tentative.html +++ b/third_party/blink/web_tests/external/wpt/web-bundle/wbn-from-network/wbn-location.tentative.html
@@ -6,18 +6,7 @@ <body> <script> promise_test(async (t) => { - // 'b1' version - assert_equals( - await getLocationPromise("-b1"), - get_host_info().HTTPS_ORIGIN + '/web-bundle/resources/wbn/location.html'); - // 'b2' version - assert_equals( - await getLocationPromise(""), - get_host_info().HTTPS_ORIGIN + '/web-bundle/resources/wbn/location.html'); -}, 'Location of a page in a Web Bundle'); - -function getLocationPromise(version_suffix) { - return new Promise((resolve, reject) => { + const location_promise = new Promise((resolve, reject) => { let win = null; window.addEventListener( 'message', @@ -26,12 +15,16 @@ resolve(event.data.location); }, false); win = window.open( - get_host_info().HTTPS_ORIGIN + '/web-bundle/resources/wbn/location' + version_suffix + '.wbn', + get_host_info().HTTPS_ORIGIN + '/web-bundle/resources/wbn/location.wbn', '_blank'); if (!win) { reject('Popup could not be opened'); } }); -} + assert_equals( + await location_promise, + get_host_info().HTTPS_ORIGIN + '/web-bundle/resources/wbn/location.html'); +}, 'Location of a page in a Web Bundle'); + </script> </body>
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/preload/subresource-integrity-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/preload/subresource-integrity-expected.txt deleted file mode 100644 index f1e852a6..0000000 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/preload/subresource-integrity-expected.txt +++ /dev/null
@@ -1,79 +0,0 @@ -This is a testharness.js-based test. -Found 75 tests; 69 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Same-origin script with correct sha256 hash. -PASS Same-origin script with correct sha384 hash. -PASS Same-origin script with correct sha512 hash. -PASS Same-origin script with empty integrity. -PASS Same-origin script with incorrect hash. -PASS Same-origin script with multiple sha256 hashes, including correct. -PASS Same-origin script with multiple sha256 hashes, including unknown algorithm. -PASS Same-origin script with sha256 mismatch, sha512 match -PASS Same-origin script with sha256 match, sha512 mismatch -PASS <crossorigin='anonymous'> script with correct hash, ACAO: * -PASS <crossorigin='anonymous'> script with incorrect hash, ACAO: * -PASS <crossorigin='use-credentials'> script with correct hash, CORS-eligible -PASS <crossorigin='use-credentials'> script with incorrect hash CORS-eligible -PASS <crossorigin='anonymous'> script with CORS-ineligible resource -PASS Cross-origin script, not CORS request, with correct hash -PASS Cross-origin script, not CORS request, with hash mismatch -PASS Cross-origin script, empty integrity -PASS Same-origin script with correct hash, options. -PASS Same-origin script with unknown algorithm only. -PASS Same-origin script with matching digest re-uses preload with matching digest. -PASS Same-origin script with matching digest re-uses preload with matching digest and options. -PASS Same-origin script with non-matching digest does not re-use preload with matching digest. -PASS Same-origin script with matching digest does not re-use preload with non-matching digest. -PASS Same-origin script with non-matching digest does not re-use preload with non-matching digest. -PASS Same-origin script with matching digest does not reuse preload without digest. -PASS [Tentative] Same-origin script with matching digest does not reuse preload with matching but stronger digest. -PASS Same-origin script with matching digest does not reuse preload with matching but weaker digest. -PASS Same-origin script with non-matching digest reuses preload with no digest but fails. -PASS Same-origin style with correct sha256 hash. -PASS Same-origin style with correct sha384 hash. -PASS Same-origin style with correct sha512 hash. -PASS Same-origin style with empty integrity. -PASS Same-origin style with incorrect hash. -PASS Same-origin style with multiple sha256 hashes, including correct. -PASS Same-origin style with multiple sha256 hashes, including unknown algorithm. -PASS Same-origin style with sha256 mismatch, sha512 match -PASS Same-origin style with sha256 match, sha512 mismatch -PASS <crossorigin='anonymous'> style with correct hash, ACAO: * -PASS <crossorigin='anonymous'> style with incorrect hash, ACAO: * -PASS <crossorigin='use-credentials'> style with correct hash, CORS-eligible -PASS <crossorigin='use-credentials'> style with incorrect hash CORS-eligible -PASS <crossorigin='anonymous'> style with CORS-ineligible resource -PASS Cross-origin style, not CORS request, with correct hash -PASS Cross-origin style, not CORS request, with hash mismatch -PASS Cross-origin style, empty integrity -PASS Same-origin style with correct hash, options. -PASS Same-origin style with unknown algorithm only. -PASS Same-origin style with matching digest re-uses preload with matching digest. -PASS Same-origin style with matching digest re-uses preload with matching digest and options. -PASS Same-origin style with non-matching digest does not re-use preload with matching digest. -PASS Same-origin style with matching digest does not re-use preload with non-matching digest. -PASS Same-origin style with non-matching digest does not re-use preload with non-matching digest. -PASS Same-origin style with matching digest does not reuse preload without digest. -PASS [Tentative] Same-origin style with matching digest does not reuse preload with matching but stronger digest. -PASS Same-origin style with matching digest does not reuse preload with matching but weaker digest. -PASS Same-origin style with non-matching digest reuses preload with no digest but fails. -PASS Same-origin image with correct sha256 hash. -PASS Same-origin image with correct sha384 hash. -PASS Same-origin image with correct sha512 hash. -PASS Same-origin image with empty integrity. -FAIL Same-origin image with incorrect hash. assert_unreached: Invalid preload load succeeded. Reached unreachable code -PASS Same-origin image with multiple sha256 hashes, including correct. -PASS Same-origin image with multiple sha256 hashes, including unknown algorithm. -PASS Same-origin image with sha256 mismatch, sha512 match -FAIL Same-origin image with sha256 match, sha512 mismatch assert_unreached: Invalid preload load succeeded. Reached unreachable code -PASS <crossorigin='anonymous'> image with correct hash, ACAO: * -FAIL <crossorigin='anonymous'> image with incorrect hash, ACAO: * assert_unreached: Invalid preload load succeeded. Reached unreachable code -PASS <crossorigin='use-credentials'> image with correct hash, CORS-eligible -FAIL <crossorigin='use-credentials'> image with incorrect hash CORS-eligible assert_unreached: Invalid preload load succeeded. Reached unreachable code -PASS <crossorigin='anonymous'> image with CORS-ineligible resource -FAIL Cross-origin image, not CORS request, with correct hash assert_unreached: Invalid preload load succeeded. Reached unreachable code -FAIL Cross-origin image, not CORS request, with hash mismatch assert_unreached: Invalid preload load succeeded. Reached unreachable code -PASS Cross-origin image, empty integrity -PASS Same-origin image with correct hash, options. -PASS Same-origin image with unknown algorithm only. -Harness: the test ran to completion. -
diff --git a/third_party/libaddressinput/chromium/address_input_strings.grd b/third_party/libaddressinput/chromium/address_input_strings.grd index 1c7ece1..086c3b72 100644 --- a/third_party/libaddressinput/chromium/address_input_strings.grd +++ b/third_party/libaddressinput/chromium/address_input_strings.grd
@@ -34,6 +34,7 @@ <output filename="address_input_strings_bs.pak" type="data_package" lang="bs" /> <output filename="address_input_strings_ca.pak" type="data_package" lang="ca" /> <output filename="address_input_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="address_input_strings_cy.pak" type="data_package" lang="cy" /> <output filename="address_input_strings_da.pak" type="data_package" lang="da" /> <output filename="address_input_strings_de.pak" type="data_package" lang="de" /> <output filename="address_input_strings_el.pak" type="data_package" lang="el" />
diff --git a/third_party/unrar/README.chromium b/third_party/unrar/README.chromium index 36d1e01..1aefd1a 100644 --- a/third_party/unrar/README.chromium +++ b/third_party/unrar/README.chromium
@@ -31,6 +31,6 @@ can be extracted inside the sandbox for analysis. - Fix a bug with NOVOLUME implementation (https://crbug.com/949787). This should be temporary, until the fix can be pulled from upstream. -- More static initializers removed (see chromium_changes2.patch) +- More static initializers removed. -All these changes are included in one patch file (chromium_changes.patch) +All these changes are included in one patch file (chromium_changes.v6.0.3.patch)
diff --git a/third_party/unrar/patches/chromium_changes.patch b/third_party/unrar/patches/chromium_changes.patch deleted file mode 100644 index c64a6bb..0000000 --- a/third_party/unrar/patches/chromium_changes.patch +++ /dev/null
@@ -1,860 +0,0 @@ -diff --git b/third_party/unrar/src/archive.cpp a/third_party/unrar/src/archive.cpp -index 9e3aa8d3870d..af16f1983293 100644 ---- b/third_party/unrar/src/archive.cpp -+++ a/third_party/unrar/src/archive.cpp -@@ -336,3 +338,12 @@ int64 Archive::Tell() - } - #endif - -+#if defined(CHROMIUM_UNRAR) -+void Archive::SetTempFileHandle(FileHandle hF) { -+ hTempFile = hF; -+} -+ -+FileHandle Archive::GetTempFileHandle() { -+ return hTempFile; -+} -+#endif -diff --git b/third_party/unrar/src/archive.hpp a/third_party/unrar/src/archive.hpp -index a9fa06c29e63..9c1456830413 100644 ---- b/third_party/unrar/src/archive.hpp -+++ a/third_party/unrar/src/archive.hpp -@@ -60,6 +60,13 @@ class Archive:public File - QuickOpen QOpen; - bool ProhibitQOpen; - #endif -+ -+#if defined(CHROMIUM_UNRAR) -+ // A handle for a temporary file that should be used when extracting the -+ // archive. This is used to extract the contents while in a sandbox. -+ FileHandle hTempFile; -+#endif -+ - public: - Archive(RAROptions *InitCmd=NULL); - ~Archive(); -@@ -101,6 +108,10 @@ class Archive:public File - void QOpenUnload() {QOpen.Unload();} - void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;} - #endif -+#if defined(CHROMIUM_UNRAR) -+ void SetTempFileHandle(FileHandle hF); -+ FileHandle GetTempFileHandle(); -+#endif - - BaseBlock ShortBlock; - MarkHeader MarkHead; -diff --git b/third_party/unrar/src/arcread.cpp a/third_party/unrar/src/arcread.cpp -index e64519a7e0df..83cac34699b7 100644 ---- b/third_party/unrar/src/arcread.cpp -+++ a/third_party/unrar/src/arcread.cpp -@@ -141,7 +144,8 @@ size_t Archive::ReadHeader15() - - if (Decrypt) - { --#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. -+#if defined(RAR_NOCRYPT) || \ -+ defined(CHROMIUM_UNRAR) // For rarext.dll and unrar_nocrypt.dll. - return 0; - #else - RequestArcPassword(); -@@ -554,7 +559,7 @@ size_t Archive::ReadHeader50() - - if (Decrypt) - { --#if defined(RAR_NOCRYPT) -+#if defined(RAR_NOCRYPT) || defined(CHROMIUM_UNRAR) - return 0; - #else - -diff --git b/third_party/unrar/src/crc.cpp a/third_party/unrar/src/crc.cpp -index 1097f4cd00d1..8488e102c28e 100644 ---- b/third_party/unrar/src/crc.cpp -+++ a/third_party/unrar/src/crc.cpp -@@ -15,6 +15,7 @@ - #include "rar.hpp" - - static uint crc_tables[8][256]; // Tables for Slicing-by-8. -+static bool is_initialized = false; - - - // Build the classic CRC32 lookup table. -@@ -49,10 +50,13 @@ static void InitTables() - } - - --struct CallInitCRC {CallInitCRC() {InitTables();}} static CallInit32; -- - uint CRC32(uint StartCRC,const void *Addr,size_t Size) - { -+ if (!is_initialized) { -+ is_initialized = true; -+ InitTables(); -+ } -+ - byte *Data=(byte *)Addr; - - // Align Data to 8 for better performance. -diff --git b/third_party/unrar/src/errhnd.cpp a/third_party/unrar/src/errhnd.cpp -index ef1c372ae491..55f098961657 100644 ---- b/third_party/unrar/src/errhnd.cpp -+++ a/third_party/unrar/src/errhnd.cpp -@@ -1,10 +1,12 @@ --#include "rar.hpp" -+// NOTE(vakh): The process.h file needs to be included first because "rar.hpp" -+// defines certain macros that cause symbol redefinition errors -+#if defined(UNRAR_NO_EXCEPTIONS) -+#include "base/check.h" -+#include "base/process/process.h" -+#endif // defined(UNRAR_NO_EXCEPTIONS) - --ErrorHandler::ErrorHandler() --{ -- Clean(); --} -+#include "rar.hpp" - - - void ErrorHandler::Clean() - { -@@ -322,7 +325,11 @@ void ErrorHandler::Throw(RAR_EXIT Code) - mprintf(L"\n%s\n",St(MProgAborted)); - #endif - SetErrorCode(Code); -+#if defined(UNRAR_NO_EXCEPTIONS) -+ CHECK(false) << "Failed with RAR_EXIT code: " << Code; -+#else - throw Code; -+#endif // defined(UNRAR_NO_EXCEPTIONS) - } - - -diff --git b/third_party/unrar/src/errhnd.hpp a/third_party/unrar/src/errhnd.hpp -index 53c713291831..b3f728e48122 100644 ---- b/third_party/unrar/src/errhnd.hpp -+++ a/third_party/unrar/src/errhnd.hpp -@@ -23,13 +23,12 @@ enum RAR_EXIT // RAR exit code. - class ErrorHandler - { - private: -- RAR_EXIT ExitCode; -- uint ErrCount; -- bool EnableBreak; -- bool Silent; -- bool DisableShutdown; // Shutdown is not suitable after last error. -+ RAR_EXIT ExitCode = RARX_SUCCESS; -+ uint ErrCount = 0; -+ bool EnableBreak = true; -+ bool Silent = false; -+ bool DisableShutdown = false; // Shutdown is not suitable after last error. - public: -- ErrorHandler(); - void Clean(); - void MemoryError(); - void OpenError(const wchar *FileName); -@@ -66,9 +65,9 @@ class ErrorHandler - void SetDisableShutdown() {DisableShutdown=true;} - bool IsShutdownEnabled() {return !DisableShutdown;} - -- bool UserBreak; // Ctrl+Break is pressed. -- bool MainExit; // main() is completed. -+ bool UserBreak = false; // Ctrl+Break is pressed. -+ bool MainExit = false; // main() is completed. - }; - - - #endif -diff --git b/third_party/unrar/src/extract.cpp a/third_party/unrar/src/extract.cpp -index ee9480d245bc..9374ff616d75 100644 ---- b/third_party/unrar/src/extract.cpp -+++ a/third_party/unrar/src/extract.cpp -@@ -261,20 +267,22 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) - if (HeaderType==HEAD_SERVICE && PrevProcessed) - SetExtraInfo(Cmd,Arc,DestFileName); - if (HeaderType==HEAD_ENDARC) - if (Arc.EndArcHead.NextVolume) - { --#ifndef NOVOLUME -+#ifdef NOVOLUME -+ return false; -+#else - if (!MergeArchive(Arc,&DataIO,false,Command)) - { - ErrHandler.SetErrorCode(RARX_WARNING); - return false; - } --#endif - Arc.Seek(Arc.CurBlockPos,SEEK_SET); - return true; -+#endif - } - else - return false; - Arc.SeekToNext(); - return true; - } -@@ -512,6 +522,11 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) - #endif - - File CurFile; -+#if defined(CHROMIUM_UNRAR) -+ // Since extraction is done in a sandbox, this must extract to the temp file -+ // handle instead of the default. -+ CurFile.SetFileHandle(Arc.GetTempFileHandle()); -+#endif - - bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; - if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) -diff --git b/third_party/unrar/src/extract.hpp a/third_party/unrar/src/extract.hpp -index 4cae23ee4faf..d74f17939c93 100644 ---- b/third_party/unrar/src/extract.hpp -+++ a/third_party/unrar/src/extract.hpp -@@ -59,6 +59,10 @@ class CmdExtract - void ExtractArchiveInit(Archive &Arc); - bool ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat); - static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize); -+ -+#if defined(CHROMIUM_UNRAR) -+ int64 GetCurrentFileSize() { return DataIO.CurUnpWrite; } -+#endif - }; - - #endif -diff --git b/third_party/unrar/src/file.cpp a/third_party/unrar/src/file.cpp -index 52c86c0621af..7dc5b724ca73 100644 ---- b/third_party/unrar/src/file.cpp -+++ a/third_party/unrar/src/file.cpp -@@ -17,6 +17,10 @@ File::File() - NoSequentialRead=false; - CreateMode=FMF_UNDEFINED; -#endif -+ -+#ifdef CHROMIUM_UNRAR -+ hOpenFile=FILE_BAD_HANDLE; -+#endif -} -@@ -51,6 +53,11 @@ bool File::Open(const wchar *Name,uint Mode) - bool UpdateMode=(Mode & FMF_UPDATE)!=0; - bool WriteMode=(Mode & FMF_WRITE)!=0; - #ifdef _WIN_ALL -+#if defined(CHROMIUM_UNRAR) -+ // Do not open a file handle since the sandbox doesn't allow it. Use the -+ // handle provided by the caller. -+ hNewFile = hOpenFile; -+#else - uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ; - if (UpdateMode) - Access|=GENERIC_WRITE; -@@ -89,6 +96,14 @@ bool File::Open(const wchar *Name,uint Mode) - if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND) - ErrorType=FILE_NOTFOUND; - -+#endif // defined(CHROMIUM_UNRAR) -+ -+#else -+ -+#if defined(CHROMIUM_UNRAR) -+ // Do not open a file handle since the sandbox doesn't allow it. Use the -+ // handle provided by the caller. -+ int handle = hOpenFile; - #else - int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY); - #ifdef O_BINARY -@@ -99,8 +114,9 @@ bool File::Open(const wchar *Name,uint Mode) - #endif - char NameA[NM]; - WideToChar(Name,NameA,ASIZE(NameA)); -- - int handle=open(NameA,flags); -+#endif // defined(CHROMIUM_UNRAR) -+ - #ifdef LOCK_EX - - #ifdef _OSF_SOURCE -@@ -159,6 +175,11 @@ bool File::WOpen(const wchar *Name) - - bool File::Create(const wchar *Name,uint Mode) - { -+#if defined(CHROMIUM_UNRAR) -+ // Since the Chromium sandbox does not allow the creation of files, use the -+ // provided file. -+ hFile = hOpenFile; -+#else - // OpenIndiana based NAS and CIFS shares fail to set the file time if file - // was created in read+write mode and some data was written and not flushed - // before SetFileTime call. So we should use the write only mode if we plan -@@ -196,6 +217,7 @@ bool File::Create(const wchar *Name,uint Mode) - hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); - #endif - #endif -+#endif // defined(CHROMIUM_UNRAR) - NewFile=true; - HandleType=FILE_HANDLENORMAL; - SkipClose=false; -@@ -230,6 +252,8 @@ bool File::Close() - { - if (!SkipClose) - { -+#if !defined(CHROMIUM_UNRAR) -+// unrar should not close the file handle since it wasn't opened by unrar. - #ifdef _WIN_ALL - // We use the standard system handle for stdout in Windows - // and it must not be closed here. -@@ -242,6 +266,7 @@ bool File::Close() - Success=fclose(hFile)!=EOF; - #endif - #endif -+#endif // defined(CHROMIUM_UNRAR) - } - hFile=FILE_BAD_HANDLE; - } -@@ -729,3 +760,9 @@ int64 File::Copy(File &Dest,int64 Length) - return CopySize; - } - #endif -+ -+#if defined(CHROMIUM_UNRAR) -+void File::SetFileHandle(FileHandle hF) { -+ hOpenFile = hF; -+} -+#endif // defined(CHROMIUM_UNRAR) -diff --git b/third_party/unrar/src/file.hpp a/third_party/unrar/src/file.hpp -index 9d2e4226a7b4..9cc7807b0fde 100644 ---- b/third_party/unrar/src/file.hpp -+++ a/third_party/unrar/src/file.hpp -@@ -70,6 +70,10 @@ class File - wchar FileName[NM]; - - FILE_ERRORTYPE ErrorType; -+ -+#if defined(CHROMIUM_UNRAR) -+ FileHandle hOpenFile; -+#endif // defined(CHROMIUM_UNRAR) - public: - File(); - virtual ~File(); -@@ -116,6 +120,14 @@ class File - #ifdef _WIN_ALL - void RemoveSequentialFlag() {NoSequentialRead=true;} - #endif -+ -+#if defined(CHROMIUM_UNRAR) -+ // Since unrar runs in a sandbox, it doesn't have the permission to open -+ // files on the filesystem. Instead, the caller opens the file and passes -+ // the file handle to unrar. This handle is then used to read the file. -+ void SetFileHandle(FileHandle file); -+#endif // defined(CHROMIUM_UNRAR) -+ - #ifdef _UNIX - int GetFD() - { -diff --git b/third_party/unrar/src/isnt.cpp a/third_party/unrar/src/isnt.cpp -index 6fadec049fe4..d30adf550925 100644 ---- b/third_party/unrar/src/isnt.cpp -+++ a/third_party/unrar/src/isnt.cpp -@@ -1,24 +1,18 @@ - #include "rar.hpp" - - #ifdef _WIN_ALL -+#include "versionhelpers.h" -+ - DWORD WinNT() - { -- static int dwPlatformId=-1; -- static DWORD dwMajorVersion,dwMinorVersion; -- if (dwPlatformId==-1) -- { -- OSVERSIONINFO WinVer; -- WinVer.dwOSVersionInfoSize=sizeof(WinVer); -- GetVersionEx(&WinVer); -- dwPlatformId=WinVer.dwPlatformId; -- dwMajorVersion=WinVer.dwMajorVersion; -- dwMinorVersion=WinVer.dwMinorVersion; -- } -- DWORD Result=0; -- if (dwPlatformId==VER_PLATFORM_WIN32_NT) -- Result=dwMajorVersion*0x100+dwMinorVersion; -- -- -- return Result; -+ if (!IsWindowsXPOrGreater()) -+ return WNT_NONE; -+ if (!IsWindowsVistaOrGreater()) -+ return WNT_WXP; -+ if (!IsWindows7OrGreater()) return WNT_VISTA; -+ if (!IsWindows8OrGreater()) return WNT_W7; -+ if (!IsWindows8Point1OrGreater()) return WNT_W8; -+ if (!IsWindows10OrGreater()) return WNT_W81; -+ return WNT_W10; - } - #endif -diff --git b/third_party/unrar/src/isnt.hpp a/third_party/unrar/src/isnt.hpp -index 85790da46290..a02174447e29 100644 ---- b/third_party/unrar/src/isnt.hpp -+++ a/third_party/unrar/src/isnt.hpp -@@ -1,6 +1,8 @@ - #ifndef _RAR_ISNT_ - #define _RAR_ISNT_ - -+#include "windows.h" -+ - enum WINNT_VERSION { - WNT_NONE=0,WNT_NT351=0x0333,WNT_NT4=0x0400,WNT_W2000=0x0500, - WNT_WXP=0x0501,WNT_W2003=0x0502,WNT_VISTA=0x0600,WNT_W7=0x0601, -@@ -9,5 +11,4 @@ enum WINNT_VERSION { - - DWORD WinNT(); - -- - #endif -diff --git b/third_party/unrar/src/model.cpp a/third_party/unrar/src/model.cpp -index 09f9650b1c72..de700a9245ee 100644 ---- b/third_party/unrar/src/model.cpp -+++ a/third_party/unrar/src/model.cpp -@@ -45,13 +45,27 @@ void ModelPPM::RestartModelRare() - InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1; - MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext(); - if (MinContext == NULL) -+ { -+#if defined(UNRAR_NO_EXCEPTIONS) -+ base::TerminateBecauseOutOfMemory(0); -+#else - throw std::bad_alloc(); -+#endif // defined(UNRAR_NO_EXCEPTIONS) -+ } -+ - MinContext->Suffix=NULL; - OrderFall=MaxOrder; - MinContext->U.SummFreq=(MinContext->NumStats=256)+1; - FoundState=MinContext->U.Stats=(RARPPM_STATE*)SubAlloc.AllocUnits(256/2); - if (FoundState == NULL) -+ { -+#if defined(UNRAR_NO_EXCEPTIONS) -+ base::TerminateBecauseOutOfMemory(0); -+#else - throw std::bad_alloc(); -+#endif // defined(UNRAR_NO_EXCEPTIONS) -+ } -+ - for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++) - { - MinContext->U.Stats[i].Symbol=i; -diff --git b/third_party/unrar/src/os.hpp a/third_party/unrar/src/os.hpp -index d4a7426d9ec4..bc1112633f7d 100644 ---- b/third_party/unrar/src/os.hpp -+++ a/third_party/unrar/src/os.hpp -@@ -32,22 +32,26 @@ - #define STRICT 1 - #endif - -+#if !defined(CHROMIUM_UNRAR) - // 'ifndef' check here is needed for unrar.dll header to avoid macro - // re-definition warnings in third party projects. - #ifndef UNICODE - #define UNICODE - #endif - - #undef WINVER - #undef _WIN32_WINNT - #define WINVER 0x0501 - #define _WIN32_WINNT 0x0501 -+#endif // CHROMIUM_UNRAR - --#if !defined(ZIPSFX) -+#if !defined(ZIPSFX) && !defined(CHROMIUM_UNRAR) - #define RAR_SMP - #endif - -+#if !defined(CHROMIUM_UNRAR) - #define WIN32_LEAN_AND_MEAN -+#endif // CHROMIUM_UNRAR - - #include <windows.h> - #include <prsht.h> -@@ -74,8 +78,11 @@ - #include <direct.h> - #include <intrin.h> - -+#if !defined(CHROMIUM_UNRAR) - #define USE_SSE - #define SSE_ALIGNMENT 16 -+#endif // CHROMIUM_UNRAR -+ - #else - #include <dirent.h> - #endif // _MSC_VER -diff --git b/third_party/unrar/src/threadmisc.cpp a/third_party/unrar/src/threadmisc.cpp -index fd408f0518ae..3136031b48ab 100644 ---- b/third_party/unrar/src/threadmisc.cpp -+++ a/third_party/unrar/src/threadmisc.cpp -@@ -45,17 +45,22 @@ static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection) - } - - --static struct GlobalPoolCreateSync -+struct GlobalPoolCreateSync - { - CRITSECT_HANDLE CritSection; - GlobalPoolCreateSync() { CriticalSectionCreate(&CritSection); } - ~GlobalPoolCreateSync() { CriticalSectionDelete(&CritSection); } --} PoolCreateSync; -+}; -+ -+static GlobalPoolCreateSync& GetPoolCreateSync() { -+ static GlobalPoolCreateSync PoolCreateSync; -+ return PoolCreateSync; -+} - - - ThreadPool* CreateThreadPool() - { -- CriticalSectionStart(&PoolCreateSync.CritSection); -+ CriticalSectionStart(&(GetPoolCreateSync().CritSection)); - - if (GlobalPoolUseCount++ == 0) - GlobalPool=new ThreadPool(MaxPoolThreads); -@@ -68,11 +73,11 @@ ThreadPool* CreateThreadPool() - if (GlobalPoolUseCount > 1) - { - ThreadPool *Pool = new ThreadPool(MaxPoolThreads); -- CriticalSectionEnd(&PoolCreateSync.CritSection); -+ CriticalSectionEnd(&(GetPoolCreateSync().CritSection)); - return Pool; - } - -- CriticalSectionEnd(&PoolCreateSync.CritSection); -+ CriticalSectionEnd(&(GetPoolCreateSync().CritSection)); - return GlobalPool; - } - -@@ -81,7 +86,7 @@ void DestroyThreadPool(ThreadPool *Pool) - { - if (Pool!=NULL) - { -- CriticalSectionStart(&PoolCreateSync.CritSection); -+ CriticalSectionStart(&(GetPoolCreateSync().CritSection)); - - if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0) - delete GlobalPool; -@@ -91,7 +96,7 @@ void DestroyThreadPool(ThreadPool *Pool) - if (Pool!=GlobalPool) - delete Pool; - -- CriticalSectionEnd(&PoolCreateSync.CritSection); -+ CriticalSectionEnd(&(GetPoolCreateSync().CritSection)); - } - } - -diff --git b/third_party/unrar/src/unicode.cpp a/third_party/unrar/src/unicode.cpp -index ffba8c11fa4b..e84d9c1de02e 100644 ---- b/third_party/unrar/src/unicode.cpp -+++ a/third_party/unrar/src/unicode.cpp -@@ -1,7 +1,7 @@ - #include "rar.hpp" - #define MBFUNCTIONS - --#if defined(_UNIX) && defined(MBFUNCTIONS) -+#if !defined(_WIN_ALL) && !defined(_APPLE) && defined(_UNIX) && defined(MBFUNCTIONS) - - static bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success); - static void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success); -@@ -30,7 +30,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize) - #elif defined(_APPLE) - WideToUtf(Src,Dest,DestSize); - --#elif defined(MBFUNCTIONS) -+#elif defined(_UNIX) && defined(MBFUNCTIONS) - if (!WideToCharMap(Src,Dest,DestSize,RetCode)) - { - mbstate_t ps; // Use thread safe external state based functions. -@@ -95,7 +95,7 @@ bool CharToWide(const char *Src,wchar *Dest,size_t DestSize) - #elif defined(_APPLE) - UtfToWide(Src,Dest,DestSize); - --#elif defined(MBFUNCTIONS) -+#elif defined(_UNIX) && defined(MBFUNCTIONS) - mbstate_t ps; - memset (&ps, 0, sizeof(ps)); - const char *SrcParam=Src; // mbsrtowcs can change the pointer. -@@ -128,8 +128,8 @@ bool CharToWide(const char *Src,wchar *Dest,size_t DestSize) - } - - --#if defined(_UNIX) && defined(MBFUNCTIONS) --// Convert and restore mapped inconvertible Unicode characters. -+#if !defined(_WIN_ALL) && !defined(_APPLE) && defined(_UNIX) && defined(MBFUNCTIONS) -+// Convert and restore mapped inconvertible Unicode characters. - // We use it for extended ASCII names in Unix. - bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success) - { -@@ -142,7 +142,7 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success) - // can produce uninitilized output while reporting success on garbage input. - // So we clean the destination to calm analyzers. - memset(Dest,0,DestSize); -- -+ - Success=true; - uint SrcPos=0,DestPos=0; - while (Src[SrcPos]!=0 && DestPos<DestSize-MB_CUR_MAX) -@@ -177,8 +177,8 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success) - #endif - - --#if defined(_UNIX) && defined(MBFUNCTIONS) -+#if !defined(_WIN_ALL) && !defined(_APPLE) && defined(_UNIX) && defined(MBFUNCTIONS) - // Convert and map inconvertible Unicode characters. - // We use it for extended ASCII names in Unix. - void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success) - { -diff --git b/third_party/unrar/src/unpack.cpp a/third_party/unrar/src/unpack.cpp -index d297211dcdb8..dee442e2d19f 100644 ---- b/third_party/unrar/src/unpack.cpp -+++ a/third_party/unrar/src/unpack.cpp -@@ -1,3 +1,9 @@ -+// NOTE(vakh): The process.h file needs to be included first because "rar.hpp" -+// defines certain macros that cause symbol redefinition errors -+#if defined(UNRAR_NO_EXCEPTIONS) -+#include "base/process/memory.h" -+#endif // defined(UNRAR_NO_EXCEPTIONS) -+ - #include "rar.hpp" - - #include "coder.cpp" -@@ -91,16 +97,27 @@ void Unpack::Init(size_t WinSize,bool Solid) - - // We do not handle growth for existing fragmented window. - if (Grow && Fragmented) -+ { -+#if defined(UNRAR_NO_EXCEPTIONS) -+ base::TerminateBecauseOutOfMemory(0); -+#else - throw std::bad_alloc(); -+#endif // defined(UNRAR_NO_EXCEPTIONS) -+ } - - byte *NewWindow=Fragmented ? NULL : (byte *)malloc(WinSize); - - if (NewWindow==NULL) -+ { - if (Grow || WinSize<0x1000000) - { - // We do not support growth for new fragmented window. - // Also exclude RAR4 and small dictionaries. -+#if defined(UNRAR_NO_EXCEPTIONS) -+ base::TerminateBecauseOutOfMemory(WinSize); -+#else - throw std::bad_alloc(); -+#endif // defined(UNRAR_NO_EXCEPTIONS) - } - else - { -@@ -112,6 +129,7 @@ void Unpack::Init(size_t WinSize,bool Solid) - FragWindow.Init(WinSize); - Fragmented=true; - } -+ } - - if (!Fragmented) - { -diff --git b/third_party/unrar/src/unpack50frag.cpp a/third_party/unrar/src/unpack50frag.cpp -index d55b3564c7d9..e45cb51a389c 100644 ---- b/third_party/unrar/src/unpack50frag.cpp -+++ a/third_party/unrar/src/unpack50frag.cpp -@@ -48,9 +48,15 @@ void FragmentedWindow::Init(size_t WinSize) - break; - Size-=Size/32; - } -- if (NewMem==NULL) -+ if (NewMem == NULL) -+ { -+#if defined(UNRAR_NO_EXCEPTIONS) -+ base::TerminateBecauseOutOfMemory(Size); -+#else - throw std::bad_alloc(); -- -+#endif // defined(UNRAR_NO_EXCEPTIONS) -+ } -+ - // Clean the window to generate the same output when unpacking corrupt - // RAR files, which may access to unused areas of sliding dictionary. - memset(NewMem,0,Size); -@@ -60,8 +66,14 @@ void FragmentedWindow::Init(size_t WinSize) - MemSize[BlockNum]=TotalSize; - BlockNum++; - } -- if (TotalSize<WinSize) // Not found enough free blocks. -+ if (TotalSize < WinSize) // Not found enough free blocks. -+ { -+#if defined(UNRAR_NO_EXCEPTIONS) -+ base::TerminateBecauseOutOfMemory(WinSize); -+#else - throw std::bad_alloc(); -+#endif // defined(UNRAR_NO_EXCEPTIONS) -+ } - } - - -diff --git b/third_party/unrar/src/unrar_wrapper.cc a/third_party/unrar/src/unrar_wrapper.cc -new file mode 100644 -index 000000000000..63b31f008861 ---- /dev/null -+++ a/third_party/unrar/src/unrar_wrapper.cc -@@ -0,0 +1,80 @@ -+// 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/unrar/src/unrar_wrapper.h" -+ -+#include <memory> -+ -+#include "base/files/file_path.h" -+#include "base/metrics/histogram_macros.h" -+#include "build/build_config.h" -+#include "third_party/unrar/src/rar.hpp" -+ -+namespace third_party_unrar { -+ -+RarReader::RarReader() {} -+ -+RarReader::~RarReader() {} -+ -+bool RarReader::Open(base::File rar_file, base::File temp_file) { -+ rar_file_ = std::move(rar_file); -+ temp_file_ = std::move(temp_file); -+ -+ archive_ = std::make_unique<Archive>(); -+ archive_->SetFileHandle(rar_file_.GetPlatformFile()); -+ archive_->SetTempFileHandle(temp_file_.GetPlatformFile()); -+ -+ bool open_success = archive_->Open(L"dummy.rar"); -+ UMA_HISTOGRAM_BOOLEAN("SBClientDownload.RarOpenSuccess", open_success); -+ if (!open_success) -+ return false; -+ -+ bool is_valid_archive = archive_->IsArchive(/*EnableBroken=*/true); -+ UMA_HISTOGRAM_BOOLEAN("SBClientDownload.RarValidArchive", is_valid_archive); -+ if (!is_valid_archive) -+ return false; -+ -+ UMA_HISTOGRAM_BOOLEAN("SBClientDownload.RarHeadersEncrypted", -+ archive_->Encrypted); -+ -+ command_ = std::make_unique<CommandData>(); -+ command_->ParseArg(const_cast<wchar_t*>(L"-p")); -+ command_->ParseArg(const_cast<wchar_t*>(L"x")); -+ command_->ParseDone(); -+ -+ extractor_ = std::make_unique<CmdExtract>(command_.get()); -+ extractor_->ExtractArchiveInit(*archive_); -+ -+ return true; -+} -+ -+bool RarReader::ExtractNextEntry() { -+ bool success = true, repeat = true; -+ while (success || repeat) { -+ temp_file_.Seek(base::File::Whence::FROM_BEGIN, 0); -+ temp_file_.SetLength(0); -+ size_t header_size = archive_->ReadHeader(); -+ repeat = false; -+ success = extractor_->ExtractCurrentFile( -+ *archive_, header_size, repeat); // |repeat| is passed by reference -+ -+ if (archive_->GetHeaderType() == HEAD_FILE) { -+#if defined(OS_WIN) -+ current_entry_.file_path = base::FilePath(archive_->FileHead.FileName); -+#else -+ std::wstring wide_filename(archive_->FileHead.FileName); -+ std::string filename(wide_filename.begin(), wide_filename.end()); -+ current_entry_.file_path = base::FilePath(filename); -+#endif -+ current_entry_.is_directory = archive_->FileHead.Dir; -+ current_entry_.is_encrypted = archive_->FileHead.Encrypted; -+ current_entry_.file_size = extractor_->GetCurrentFileSize(); -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+} // namespace third_party_unrar -diff --git b/third_party/unrar/src/unrar_wrapper.h a/third_party/unrar/src/unrar_wrapper.h -new file mode 100644 -index 000000000000..1626af000903 ---- /dev/null -+++ a/third_party/unrar/src/unrar_wrapper.h -@@ -0,0 +1,72 @@ -+// 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 THIRD_PARTY_UNRAR_SRC_UNRAR_WRAPPER_H_ -+#define THIRD_PARTY_UNRAR_SRC_UNRAR_WRAPPER_H_ -+ -+#include "base/files/file.h" -+#include "base/files/file_path.h" -+#include "base/files/platform_file.h" -+#include "base/memory/scoped_refptr.h" -+ -+// Forward declare the unrar symbols needed for extraction, so users of -+// RarReader don't need all the symbols from unrar. -+class Archive; -+class CmdExtract; -+class CommandData; -+ -+namespace third_party_unrar { -+ -+// This class is used for extracting RAR files, one entry at a time. -+class RarReader { -+ public: -+ struct EntryInfo { -+ // The relative path of this entry, within the archive. -+ base::FilePath file_path; -+ -+ // Whether the entry is a directory or a file. -+ bool is_directory; -+ -+ // Whether the entry has encrypted contents. -+ bool is_encrypted; -+ -+ // The actual size of the entry. -+ size_t file_size; -+ }; -+ -+ RarReader(); -+ ~RarReader(); -+ -+ // Opens the RAR archive in |rar_file|, and uses |temp_file| for extracting -+ // each entry. -+ bool Open(base::File rar_file, base::File temp_file); -+ -+ // Extracts the next entry in the RAR archive. Returns true on success and -+ // updates the information in |current_entry()|. -+ bool ExtractNextEntry(); -+ -+ // Returns the EntryInfo for the most recently extracted entry in the RAR -+ // archive. -+ const EntryInfo& current_entry() { return current_entry_; } -+ -+ private: -+ // The temporary file used for extracting each entry. This allows RAR -+ // extraction to safely occur within a sandbox. -+ base::File temp_file_; -+ -+ // The RAR archive being extracted. -+ base::File rar_file_; -+ -+ // Information for the current entry in the RAR archive. -+ EntryInfo current_entry_; -+ -+ // Unrar data structures needed for extraction. -+ std::unique_ptr<Archive> archive_; -+ std::unique_ptr<CmdExtract> extractor_; -+ std::unique_ptr<CommandData> command_; -+}; -+ -+} // namespace third_party_unrar -+ -+#endif // THIRD_PARTY_UNRAR_SRC_UNRAR_WRAPPER_H_
diff --git a/third_party/unrar/patches/chromium_changes.v6.0.3.patch b/third_party/unrar/patches/chromium_changes.v6.0.3.patch index b9f0fe2..9829c783 100644 --- a/third_party/unrar/patches/chromium_changes.v6.0.3.patch +++ b/third_party/unrar/patches/chromium_changes.v6.0.3.patch
@@ -1,5 +1,5 @@ diff --git a/third_party/unrar/src/archive.cpp b/third_party/unrar/src/archive.cpp -index 8c5a1da81d14..cac841747d86 100644 +index 8c5a1da81d14239cb363146cdee7620fc02c318b..cac841747d867bd82ff91fb43e52fe2bf758b864 100644 --- a/third_party/unrar/src/archive.cpp +++ b/third_party/unrar/src/archive.cpp @@ -336,3 +336,12 @@ int64 Archive::Tell() @@ -16,7 +16,7 @@ +} +#endif diff --git a/third_party/unrar/src/archive.hpp b/third_party/unrar/src/archive.hpp -index d9518f1dc491..08fef7b0e6c0 100644 +index d9518f1dc491a225c61eb82a47285fa0b0ade8cd..08fef7b0e6c0ec066cd0133b5072891e2b43ac94 100644 --- a/third_party/unrar/src/archive.hpp +++ b/third_party/unrar/src/archive.hpp @@ -57,6 +57,13 @@ class Archive:public File @@ -45,7 +45,7 @@ BaseBlock ShortBlock; MarkHeader MarkHead; diff --git a/third_party/unrar/src/arcread.cpp b/third_party/unrar/src/arcread.cpp -index d1df6c04108c..468d387a2472 100644 +index d1df6c04108cddcf18af7058046a0468f627f72c..468d387a24721b651fde2745dd6c2434d9a140e0 100644 --- a/third_party/unrar/src/arcread.cpp +++ b/third_party/unrar/src/arcread.cpp @@ -142,7 +142,8 @@ size_t Archive::ReadHeader15() @@ -68,7 +68,7 @@ #else diff --git a/third_party/unrar/src/crc.cpp b/third_party/unrar/src/crc.cpp -index cf23bbf4f2af..4c86c09e3b4f 100644 +index cf23bbf4f2afa61f1d17ac854d73a1a1452a4e43..4c86c09e3b4f20c37e75140f755811ec476fd5b0 100644 --- a/third_party/unrar/src/crc.cpp +++ b/third_party/unrar/src/crc.cpp @@ -15,6 +15,7 @@ @@ -96,10 +96,10 @@ // Align Data to 8 for better performance. diff --git a/third_party/unrar/src/errhnd.cpp b/third_party/unrar/src/errhnd.cpp -index 18e91973e61b..dce0fbc09351 100644 +index 18e91973e61b7569b5cbf5f5e7b22e4b90452bac..ddbc751b57f8635f5985d076bed916b13c7c576f 100644 --- a/third_party/unrar/src/errhnd.cpp +++ b/third_party/unrar/src/errhnd.cpp -@@ -1,9 +1,11 @@ +@@ -1,10 +1,13 @@ -#include "rar.hpp" +// NOTE(vakh): The process.h file needs to be included first because "rar.hpp" +// defines certain macros that cause symbol redefinition errors @@ -114,9 +114,11 @@ -} +#include "rar.hpp" ++#include <ostream> void ErrorHandler::Clean() -@@ -334,7 +336,11 @@ void ErrorHandler::Throw(RAR_EXIT Code) + { +@@ -334,7 +337,11 @@ void ErrorHandler::Throw(RAR_EXIT Code) mprintf(L"\n%s\n",St(MProgAborted)); #endif SetErrorCode(Code); @@ -129,7 +131,7 @@ diff --git a/third_party/unrar/src/errhnd.hpp b/third_party/unrar/src/errhnd.hpp -index 06f4f616fd96..3c5c54c490f7 100644 +index 06f4f616fd96b620ce717f072c0f34d42dd8f59f..3c5c54c490f7ae9b8b2cc30f2d8e04c15bccc398 100644 --- a/third_party/unrar/src/errhnd.hpp +++ b/third_party/unrar/src/errhnd.hpp @@ -23,14 +23,13 @@ enum RAR_EXIT // RAR exit code. @@ -165,7 +167,7 @@ diff --git a/third_party/unrar/src/extract.cpp b/third_party/unrar/src/extract.cpp -index abcd3c3385c5..2c264b107040 100644 +index abcd3c3385c5db501402ab91b79efb7a9eb6c3d7..2c264b107040130d2d4fd8172d4a34e52dee2a24 100644 --- a/third_party/unrar/src/extract.cpp +++ b/third_party/unrar/src/extract.cpp @@ -524,6 +524,11 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) @@ -188,7 +190,7 @@ \ No newline at end of file +#endif diff --git a/third_party/unrar/src/extract.hpp b/third_party/unrar/src/extract.hpp -index 159759b563f5..9a659591d4f3 100644 +index 159759b563f5f056e647b2e2e63f1162cdf118af..9a659591d4f3578061c45bbbdb055d439b44a0a6 100644 --- a/third_party/unrar/src/extract.hpp +++ b/third_party/unrar/src/extract.hpp @@ -37,8 +37,8 @@ class CmdExtract @@ -214,7 +216,7 @@ #endif diff --git a/third_party/unrar/src/file.cpp b/third_party/unrar/src/file.cpp -index 5a8099ec5bd1..cd6be338e486 100644 +index 5a8099ec5bd1c8a8cb5b2d1a78d58df655d01948..cd6be338e486f4376ce4df9c34b9ca0553ccd21a 100644 --- a/third_party/unrar/src/file.cpp +++ b/third_party/unrar/src/file.cpp @@ -19,6 +19,10 @@ File::File() @@ -312,7 +314,7 @@ +} +#endif // defined(CHROMIUM_UNRAR) diff --git a/third_party/unrar/src/file.hpp b/third_party/unrar/src/file.hpp -index 1c436d4ef7bc..baf366dfa4a3 100644 +index 1c436d4ef7bc0c9df6b468caf651e9bc2ec1f9da..baf366dfa4a34b2691bca999a4704f66e7ce0a7f 100644 --- a/third_party/unrar/src/file.hpp +++ b/third_party/unrar/src/file.hpp @@ -76,6 +76,10 @@ class File @@ -342,7 +344,7 @@ int GetFD() { diff --git a/third_party/unrar/src/isnt.cpp b/third_party/unrar/src/isnt.cpp -index 6fadec049fe4..d30adf550925 100644 +index 6fadec049fe4cf9865c41c6dce8d6c459b6cd184..d30adf550925f90492a602d2dc1a757465a0bdcf 100644 --- a/third_party/unrar/src/isnt.cpp +++ b/third_party/unrar/src/isnt.cpp @@ -1,24 +1,18 @@ @@ -382,7 +384,7 @@ } #endif diff --git a/third_party/unrar/src/isnt.hpp b/third_party/unrar/src/isnt.hpp -index 85790da46290..a02174447e29 100644 +index 85790da462902fe88c6bc2ba0364b57e1e343ebb..a02174447e29fd2f248c0f37f748c8df85445d02 100644 --- a/third_party/unrar/src/isnt.hpp +++ b/third_party/unrar/src/isnt.hpp @@ -1,6 +1,8 @@ @@ -401,7 +403,7 @@ - #endif diff --git a/third_party/unrar/src/model.cpp b/third_party/unrar/src/model.cpp -index 83391c5a4510..1ca9f03e9bcc 100644 +index 83391c5a45107e2c68d3d990946f7f0426e5a542..1ca9f03e9bcc54c1febbe5fb1820a312739b1ed0 100644 --- a/third_party/unrar/src/model.cpp +++ b/third_party/unrar/src/model.cpp @@ -43,13 +43,27 @@ void ModelPPM::RestartModelRare() @@ -433,7 +435,7 @@ { MinContext->U.Stats[i].Symbol=i; diff --git a/third_party/unrar/src/os.hpp b/third_party/unrar/src/os.hpp -index b69f34878b3d..51d547b0f68b 100644 +index b69f34878b3dff1acea25635ce44958f8784b01b..51d547b0f68ba0840bcf37d9ace64a2a424acedf 100644 --- a/third_party/unrar/src/os.hpp +++ b/third_party/unrar/src/os.hpp @@ -32,6 +32,7 @@ @@ -474,7 +476,7 @@ #include <dirent.h> #endif // _MSC_VER diff --git a/third_party/unrar/src/secpassword.cpp b/third_party/unrar/src/secpassword.cpp -index 4865b3fd02e2..c292b0e00285 100644 +index 4865b3fd02e25312d4390e34cad87c513adcfbe7..c292b0e002853fa815ec84b4870ec7636531c58c 100644 --- a/third_party/unrar/src/secpassword.cpp +++ b/third_party/unrar/src/secpassword.cpp @@ -25,6 +25,7 @@ class CryptLoader @@ -540,7 +542,7 @@ ErrHandler.SysErrMsg(); ErrHandler.Exit(RARX_FATAL); diff --git a/third_party/unrar/src/unicode.cpp b/third_party/unrar/src/unicode.cpp -index 641f6c892a3f..48d7bb2fc44e 100644 +index 641f6c892a3f33f271dceac276f1c550af500ed2..48d7bb2fc44e791d9b1fc4fd79e747fc4bbde2c8 100644 --- a/third_party/unrar/src/unicode.cpp +++ b/third_party/unrar/src/unicode.cpp @@ -576,7 +576,6 @@ int64 atoilw(const wchar *s) @@ -564,7 +566,7 @@ char* SupportDBCS::charnext(const char *s) { diff --git a/third_party/unrar/src/unicode.hpp b/third_party/unrar/src/unicode.hpp -index 031ac09ab94b..c66cc95a34cc 100644 +index 031ac09ab94b6f5fd5f38d25c0bac5aa93dfab7c..c66cc95a34cc3ac1edcba80b22d61d73864928cf 100644 --- a/third_party/unrar/src/unicode.hpp +++ b/third_party/unrar/src/unicode.hpp @@ -33,6 +33,7 @@ class SupportDBCS @@ -599,7 +601,7 @@ #else #define charnext(s) ((s)+1) diff --git a/third_party/unrar/src/unpack.cpp b/third_party/unrar/src/unpack.cpp -index 037c35546a89..7f579ff06ab3 100644 +index 037c35546a894bba79225b1e0f3750807a3284af..7f579ff06ab38cf4a3f268252106e22cba420358 100644 --- a/third_party/unrar/src/unpack.cpp +++ b/third_party/unrar/src/unpack.cpp @@ -1,3 +1,9 @@ @@ -649,7 +651,7 @@ if (!Fragmented) { diff --git a/third_party/unrar/src/unpack50frag.cpp b/third_party/unrar/src/unpack50frag.cpp -index 3c008ff24539..16d5b1c3d5ef 100644 +index 3c008ff245390a35334c43b71e5fdd283b8815d1..16d5b1c3d5ef368e4888831bf16edd4f1025f655 100644 --- a/third_party/unrar/src/unpack50frag.cpp +++ b/third_party/unrar/src/unpack50frag.cpp @@ -46,8 +46,14 @@ void FragmentedWindow::Init(size_t WinSize)
diff --git a/third_party/unrar/patches/chromium_changes2.patch b/third_party/unrar/patches/chromium_changes2.patch deleted file mode 100644 index c0c71db..0000000 --- a/third_party/unrar/patches/chromium_changes2.patch +++ /dev/null
@@ -1,125 +0,0 @@ -diff --git a/third_party/unrar/src/secpassword.cpp b/third_party/unrar/src/secpassword.cpp -index 4865b3fd02e2..c292b0e00285 100644 ---- a/third_party/unrar/src/secpassword.cpp -+++ b/third_party/unrar/src/secpassword.cpp -@@ -25,6 +25,7 @@ class CryptLoader - } - ~CryptLoader() - { -+ // We need to call FreeLibrary when RAR is exiting. - if (hCrypt!=NULL) - FreeLibrary(hCrypt); - hCrypt=NULL; -@@ -46,12 +47,14 @@ class CryptLoader - } - } - -+ static CryptLoader& GetInstance() { -+ static CryptLoader cryptLoader; -+ return cryptLoader; -+ } -+ - CRYPTPROTECTMEMORY pCryptProtectMemory; - CRYPTUNPROTECTMEMORY pCryptUnprotectMemory; - }; -- --// We need to call FreeLibrary when RAR is exiting. --CryptLoader GlobalCryptLoader; - #endif - - SecPassword::SecPassword() -@@ -169,16 +172,15 @@ void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess) - // increases data size not allowing in place conversion. - #if defined(_WIN_ALL) - // Try to utilize the secure Crypt[Un]ProtectMemory if possible. -- if (GlobalCryptLoader.pCryptProtectMemory==NULL) -- GlobalCryptLoader.Load(); -+ if (CryptLoader::GetInstance().pCryptProtectMemory == NULL) -+ CryptLoader::GetInstance().Load(); - size_t Aligned=DataSize-DataSize%CRYPTPROTECTMEMORY_BLOCK_SIZE; - DWORD Flags=CrossProcess ? CRYPTPROTECTMEMORY_CROSS_PROCESS : CRYPTPROTECTMEMORY_SAME_PROCESS; - if (Encode) - { -- if (GlobalCryptLoader.pCryptProtectMemory!=NULL) -- { -- if (!GlobalCryptLoader.pCryptProtectMemory(Data,DWORD(Aligned),Flags)) -- { -+ if (CryptLoader::GetInstance().pCryptProtectMemory != NULL) { -+ if (!CryptLoader::GetInstance().pCryptProtectMemory(Data, DWORD(Aligned), -+ Flags)) { - ErrHandler.GeneralErrMsg(L"CryptProtectMemory failed"); - ErrHandler.SysErrMsg(); - ErrHandler.Exit(RARX_FATAL); -@@ -188,10 +190,9 @@ void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess) - } - else - { -- if (GlobalCryptLoader.pCryptUnprotectMemory!=NULL) -- { -- if (!GlobalCryptLoader.pCryptUnprotectMemory(Data,DWORD(Aligned),Flags)) -- { -+ if (CryptLoader::GetInstance().pCryptUnprotectMemory != NULL) { -+ if (!CryptLoader::GetInstance().pCryptUnprotectMemory( -+ Data, DWORD(Aligned), Flags)) { - ErrHandler.GeneralErrMsg(L"CryptUnprotectMemory failed"); - ErrHandler.SysErrMsg(); - ErrHandler.Exit(RARX_FATAL); -diff --git a/third_party/unrar/src/unicode.cpp b/third_party/unrar/src/unicode.cpp -index e84d9c1de02e..b2015b8be649 100644 ---- a/third_party/unrar/src/unicode.cpp -+++ b/third_party/unrar/src/unicode.cpp -@@ -569,7 +569,6 @@ int64 atoilw(const wchar *s) - - - #ifdef DBCS_SUPPORTED --SupportDBCS gdbcs; - - SupportDBCS::SupportDBCS() - { -@@ -586,6 +585,11 @@ void SupportDBCS::Init() - IsLeadByte[I]=IsDBCSLeadByte(I)!=0; - } - -+// static -+SupportDBCS& SupportDBCS::GetInstance() { -+ static SupportDBCS supportDBCS; -+ return supportDBCS; -+} - - char* SupportDBCS::charnext(const char *s) - { -diff --git a/third_party/unrar/src/unicode.hpp b/third_party/unrar/src/unicode.hpp -index e38667d9868d..0efb4c91cfe4 100644 ---- a/third_party/unrar/src/unicode.hpp -+++ b/third_party/unrar/src/unicode.hpp -@@ -33,6 +33,7 @@ class SupportDBCS - public: - SupportDBCS(); - void Init(); -+ static SupportDBCS& GetInstance(); - - char* charnext(const char *s); - size_t strlend(const char *s); -@@ -44,15 +45,13 @@ class SupportDBCS - bool DBCSMode; - }; - --extern SupportDBCS gdbcs; -- --inline char* charnext(const char *s) {return (char *)(gdbcs.DBCSMode ? gdbcs.charnext(s):s+1);} --inline size_t strlend(const char *s) {return (uint)(gdbcs.DBCSMode ? gdbcs.strlend(s):strlen(s));} --inline char* strchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strchrd(s,c):strchr(s,c));} --inline char* strrchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strrchrd(s,c):strrchr(s,c));} --inline void copychrd(char *dest,const char *src) {if (gdbcs.DBCSMode) gdbcs.copychrd(dest,src); else *dest=*src;} --inline bool IsDBCSMode() {return(gdbcs.DBCSMode);} --inline void InitDBCS() {gdbcs.Init();} -+inline char* charnext(const char *s) {return (char *)(SupportDBCS::GetInstance().DBCSMode ? SupportDBCS::GetInstance().charnext(s):s+1);} -+inline size_t strlend(const char *s) {return (uint)(SupportDBCS::GetInstance().DBCSMode ? SupportDBCS::GetInstance().strlend(s):strlen(s));} -+inline char* strchrd(const char *s, int c) {return (char *)(SupportDBCS::GetInstance().DBCSMode ? SupportDBCS::GetInstance().strchrd(s,c):strchr(s,c));} -+inline char* strrchrd(const char *s, int c) {return (char *)(SupportDBCS::GetInstance().DBCSMode ? SupportDBCS::GetInstance().strrchrd(s,c):strrchr(s,c));} -+inline void copychrd(char *dest,const char *src) {if (SupportDBCS::GetInstance().DBCSMode) SupportDBCS::GetInstance().copychrd(dest,src); else *dest=*src;} -+inline bool IsDBCSMode() {return(SupportDBCS::GetInstance().DBCSMode);} -+inline void InitDBCS() {SupportDBCS::GetInstance().Init();} - - #else - #define charnext(s) ((s)+1)
diff --git a/third_party/unrar/src/errhnd.cpp b/third_party/unrar/src/errhnd.cpp index dce0fbc09..ddbc751 100644 --- a/third_party/unrar/src/errhnd.cpp +++ b/third_party/unrar/src/errhnd.cpp
@@ -7,6 +7,7 @@ #include "rar.hpp" +#include <ostream> void ErrorHandler::Clean() {
diff --git a/third_party/zlib/contrib/optimizations/inflate.c b/third_party/zlib/contrib/optimizations/inflate.c index 5258d58..4841cd9 100644 --- a/third_party/zlib/contrib/optimizations/inflate.c +++ b/third_party/zlib/contrib/optimizations/inflate.c
@@ -131,6 +131,7 @@ state->mode = HEAD; state->last = 0; state->havedict = 0; + state->flags = -1; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; @@ -682,7 +683,6 @@ state->mode = FLAGS; break; } - state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ @@ -709,6 +709,7 @@ break; } state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; @@ -1233,7 +1234,7 @@ case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; @@ -1423,6 +1424,7 @@ z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; @@ -1455,11 +1457,15 @@ /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; - if (state->mode == HEAD) - state->wrap = 0; /* never processed header, so assume raw */ + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; + state->flags = flags; state->mode = TYPE; return Z_OK; }
diff --git a/third_party/zlib/google/zip_unittest.cc b/third_party/zlib/google/zip_unittest.cc index 0006dbe..435d7b0 100644 --- a/third_party/zlib/google/zip_unittest.cc +++ b/third_party/zlib/google/zip_unittest.cc
@@ -644,8 +644,20 @@ GetRelativePaths(test_dir_, base::FileEnumerator::FileType::FILES); for (const std::string& path : got_paths) { - EXPECT_TRUE(want_paths.erase(path)) - << "Found unexpected file: " << std::quoted(path); + const bool ok = want_paths.erase(path); + +#ifdef OS_WIN + if (!ok) { + // See crbug.com/1313991: Different versions of Windows treat these + // filenames differently. No hard error here if there is an unexpected + // file. + LOG(WARNING) << "Found unexpected file: " << std::quoted(path); + continue; + } +#else + EXPECT_TRUE(ok) << "Found unexpected file: " << std::quoted(path); +#endif + std::string contents; EXPECT_TRUE(base::ReadFileToString(test_dir_.AppendASCII(path), &contents)); EXPECT_EQ(base::StrCat({"This is: ", path}), contents); @@ -847,8 +859,15 @@ GetRelativePaths(test_dir_, base::FileEnumerator::FileType::FILES); for (const std::string& path : got_paths) { - EXPECT_TRUE(want_paths.erase(path)) - << "Found unexpected file: " << std::quoted(path); + const bool ok = want_paths.erase(path); +#ifdef OS_WIN + // See crbug.com/1313991: Different versions of Windows treat reserved + // Windows filenames differently. No hard error here if there is an + // unexpected file. + LOG_IF(WARNING, !ok) << "Found unexpected file: " << std::quoted(path); +#else + EXPECT_TRUE(ok) << "Found unexpected file: " << std::quoted(path); +#endif } for (const std::string& path : want_paths) {
diff --git a/third_party/zlib/inflate.c b/third_party/zlib/inflate.c index 89b20b9..7543c33d 100644 --- a/third_party/zlib/inflate.c +++ b/third_party/zlib/inflate.c
@@ -130,6 +130,7 @@ state->mode = HEAD; state->last = 0; state->havedict = 0; + state->flags = -1; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; @@ -671,7 +672,6 @@ state->mode = FLAGS; break; } - state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ @@ -698,6 +698,7 @@ break; } state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; @@ -1223,7 +1224,7 @@ case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; @@ -1403,6 +1404,7 @@ z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; @@ -1435,11 +1437,15 @@ /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; - if (state->mode == HEAD) - state->wrap = 0; /* never processed header, so assume raw */ + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; + state->flags = flags; state->mode = TYPE; return Z_OK; }
diff --git a/third_party/zlib/inflate.h b/third_party/zlib/inflate.h index a46cce6..98679fa 100644 --- a/third_party/zlib/inflate.h +++ b/third_party/zlib/inflate.h
@@ -86,7 +86,8 @@ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 9f199e93..9463395 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -10666,22 +10666,6 @@ <description>The user toogled a media permission state.</description> </action> -<action name="IOS.ReadingList.MessagesPromptToggle.Off"> - <owner>thegreenfrog@chromium.org</owner> - <owner>olivierrobin@chromium.org</owner> - <description> - The user toggled the Reading List Messages prompt setting to off. iOS only. - </description> -</action> - -<action name="IOS.ReadingList.MessagesPromptToggle.On"> - <owner>thegreenfrog@chromium.org</owner> - <owner>olivierrobin@chromium.org</owner> - <description> - The user toggled the Reading List Messages prompt setting to on. iOS only. - </description> -</action> - <action name="IOS.SearchEngines.RecentlyViewed.Delete"> <owner>sczs@chromium.org</owner> <owner>gambard@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7c883b4c4..2c1ad7d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -79319,6 +79319,7 @@ <enum name="SafeBrowsingPageLoadTokenClearReason"> <int value="0" label="Safe Browsing state changed"/> <int value="1" label="Cookies deleted"/> + <int value="2" label="Sync state changed"/> </enum> <enum name="SafeBrowsingParseV4HashResult"> @@ -94165,6 +94166,11 @@ <int value="11" label="(Light, Muted): success"/> </enum> +<enum name="WallpaperGooglePhotosSource"> + <int value="0" label="Photos"/> + <int value="1" label="Albums"/> +</enum> + <enum name="WallpaperImage"> <summary> Enumeration for online wallpaper images. The label has the format of @@ -94654,6 +94660,19 @@ <int value="1" label="WebApk infobar shown from the add to homescreen menu"/> </enum> +<enum name="WebApkInstallResult"> + <int value="0" label="Success"/> + <int value="1" label="Play install failed"/> + <int value="2" label="Install timed out"/> + <int value="3" label="No installer"/> + <int value="4" label="No server"/> + <int value="5" label="Server error"/> + <int value="6" label="Request timed out"/> + <int value="7" label="Request invalid"/> + <int value="8" label="No enough space"/> + <int value="9" label="Download icon and hash error"/> +</enum> + <enum name="WebApkInstallResultChromeOS"> <int value="0" label="Success">Installed successfully.</int> <int value="1" label="App invalid">
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 133edfb..9d06f83b8 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1858,6 +1858,17 @@ </summary> </histogram> +<histogram name="Arc.Wayland.LateTiming.Duration" units="ms" + expires_after="2022-10-05"> + <owner>alanding@google.com</owner> + <owner>arc-performance@google.com</owner> + <summary> + The duration of the Wayland client event processing time in ARC. This metric + is recorded when the processing end time is late or the duration exceeded + the expected timing threshold. + </summary> +</histogram> + <histogram name="Arc.WindowPredictorLaunch" enum="WindowPredictorLaunchType" expires_after="2022-10-01"> <owner>sstan@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 70534438..10d7b5b4 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4128,6 +4128,16 @@ <token key="Api" variants="GooglePhotosApi"/> </histogram> +<histogram name="Ash.Wallpaper.GooglePhotos.Source" + enum="WallpaperGooglePhotosSource" expires_after="2022-11-15"> + <owner>xiaohuic@google.com</owner> + <owner>assistive-eng@google.com</owner> + <summary> + Records the section of the Wallpaper App from which a Google Photos + wallpaper was selected. Emitted regardless of the selection's success. + </summary> +</histogram> + <histogram name="Ash.Wallpaper.Image" enum="WallpaperImage" expires_after="2022-05-25"> <owner>jasontt@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml index 0b95e1a..a8982cb 100644 --- a/tools/metrics/histograms/metadata/ios/histograms.xml +++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -1089,53 +1089,6 @@ </summary> </histogram> -<histogram name="IOS.ReadingList.Javascript.ExecutionTime" units="ms" - expires_after="2022-08-14"> - <owner>thegreenfrog@chromium.org</owner> - <owner>michaeldo@chromium.org</owner> - <summary> - Tracks the execution time of the distillability scoring JavaScript for the - Reading List Messages presentation heuristic. Reported for each main frame - navigation. - </summary> -</histogram> - -<histogram name="IOS.ReadingList.Javascript.LongPageDistillabilityScore" - units="Score" expires_after="2022-06-11"> - <owner>thegreenfrog@chromium.org</owner> - <owner>michaeldo@chromium.org</owner> - <summary> - The calculated distillability score for a page returned by - DistillablePageDetector::GetLongPageModel(). Score is translated by +1 to - make histogram logging simpler by keeping all scores positive. It is - multiplied by 100 to get granular scoring logging to the hundredth digit. - Reported for each main frame navigation. - </summary> -</histogram> - -<histogram name="IOS.ReadingList.Javascript.RegularDistillabilityScore" - units="Score" expires_after="2022-08-14"> - <owner>thegreenfrog@chromium.org</owner> - <owner>michaeldo@chromium.org</owner> - <summary> - The calculated distillability score for a page returned by - DistillablePageDetector::GetNewModel(). Score is translated by +1 to make - histogram logging simpler by keeping all scores positive. It is multiplied - by 100 to get granular scoring logging to the hundredth digit. Reported for - each main frame navigation. - </summary> -</histogram> - -<histogram name="IOS.ReadingList.Javascript.TimeToRead" units="Minutes" - expires_after="2022-08-14"> - <owner>thegreenfrog@chromium.org</owner> - <owner>michaeldo@chromium.org</owner> - <summary> - The estimated "time to read" calculated for a page. Reported for - each main frame navigation. - </summary> -</histogram> - <histogram name="IOS.ReadingList.PageTooLargeFailure" units="KB" expires_after="2022-06-11"> <owner>olivierrobin@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml index 8f4772d..8eff4fe 100644 --- a/tools/metrics/histograms/metadata/optimization/histograms.xml +++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -153,6 +153,17 @@ </summary> </histogram> +<histogram + name="OptimizationGuide.EntityAnnotatorNativeLibrary.InitiatedSuccessfully" + units="BooleanSuccess" expires_after="M106"> + <owner>sophiechang@chromium.org</owner> + <owner>chrome-intelligence-core@google.com</owner> + <summary> + Records whether the entity annotator native library was initiated + successfully if an attempt to load it was made. + </summary> +</histogram> + <histogram name="OptimizationGuide.HintCache.HintType.Loaded" enum="HintCacheStoreEntryType" expires_after="M106"> <owner>mcrouse@chromium.org</owner> @@ -713,6 +724,18 @@ </summary> </histogram> +<histogram + name="OptimizationGuide.PageEntitiesModelExecutor.CreatedSuccessfully" + enum="BooleanSuccess" expires_after="M106"> + <owner>sophiechang@chromium.org</owner> + <owner>chrome-intelligence-core@google.com</owner> + <summary> + Records whether the page entities model executor was created successfully + from a model file. Recorded each time it was attempted, which can be + multiple times a session if a model update was received during the session. + </summary> +</histogram> + <histogram name="OptimizationGuide.PageTextDump.AbandonedRequests" units="count" expires_after="M106"> <owner>robertogden@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml index 2eec70cb..9d886cad 100644 --- a/tools/metrics/histograms/metadata/v8/histograms.xml +++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -727,6 +727,50 @@ </summary> </histogram> +<histogram name="V8.GC.Cycle.MainThread.Full.Incremental.Mark" units="ms" + expires_after="M109"> + <owner>nikolaos@chromium.org</owner> + <owner>v8-memory-sheriffs@google.com</owner> + <summary> + Overall duration of incremental marking steps on the main thread during a + full garbage collection of the unified heap. Reported at the end of the + garbage collection cycle. + </summary> +</histogram> + +<histogram name="V8.GC.Cycle.MainThread.Full.Incremental.Mark.Cpp" units="ms" + expires_after="M109"> + <owner>omerkatz@chromium.org</owner> + <owner>v8-memory-sheriffs@google.com</owner> + <summary> + Overall duration of incremental marking steps on the main thread during a + full garbage collection of the managed C++ heap. Reported at the end of the + garbage collection cycle. + </summary> +</histogram> + +<histogram name="V8.GC.Cycle.MainThread.Full.Incremental.Sweep" units="ms" + expires_after="M109"> + <owner>nikolaos@chromium.org</owner> + <owner>v8-memory-sheriffs@google.com</owner> + <summary> + Overall duration of incremental sweeping steps on the main thread during a + full garbage collection of the unified heap. Reported at the end of the + garbage collection cycle. + </summary> +</histogram> + +<histogram name="V8.GC.Cycle.MainThread.Full.Incremental.Sweep.Cpp" units="ms" + expires_after="M109"> + <owner>omerkatz@chromium.org</owner> + <owner>v8-memory-sheriffs@google.com</owner> + <summary> + Overall duration of incremental sweeping steps on the main thread during a + full garbage collection of the managed C++ heap. Reported at the end of the + garbage collection cycle. + </summary> +</histogram> + <histogram name="V8.GC.Cycle.MainThread.Full.Mark" units="ms" expires_after="M109"> <owner>nikolaos@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/web_apk/histograms.xml b/tools/metrics/histograms/metadata/web_apk/histograms.xml index 53c484c..47b5c1c5 100644 --- a/tools/metrics/histograms/metadata/web_apk/histograms.xml +++ b/tools/metrics/histograms/metadata/web_apk/histograms.xml
@@ -108,6 +108,19 @@ </summary> </histogram> +<histogram name="WebApk.Install.InstallResult" enum="WebApkInstallResult" + expires_after="2022-08-28"> + <owner>eirage@chromium.org</owner> + <owner>hartmanng@chromium.org</owner> + <owner> + src/chrome/android/java/src/org/chromium/chrome/browser/webapps/OWNERS + </owner> + <summary> + Record whether installing a WebAPK succeeded. If not record the reason that + the install failed. + </summary> +</histogram> + <histogram name="WebApk.Install.PathToInstall" enum="PwaInstallPath" expires_after="2022-08-14"> <owner>finnur@chromium.org</owner>
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py index f9b6752..7f8ecbc 100644 --- a/tools/perf/benchmarks/media.py +++ b/tools/perf/benchmarks/media.py
@@ -45,6 +45,11 @@ options.SetTimelineBasedMetrics(['mediaMetric', 'cpuTimeMetric']) return options + def SetExtraBrowserOptions(self, options): + # bf-cache messes with the time_to_play numbers when we do several runs + # in a row. More info crbug.com/1309294 + options.AppendExtraBrowserArgs('--disable-features=BackForwardCache') + @benchmark.Info(emails=['dalecurtis@chromium.org'], component='Internals>Media', @@ -92,6 +97,7 @@ return 'media.mobile' def SetExtraBrowserOptions(self, options): + super(MediaMobile, self).SetExtraBrowserOptions(options) # By default, Chrome on Android does not allow autoplay # of media: it requires a user gesture event to start a video. # The following option works around that.
diff --git a/ui/base/test/cocoa_helper.h b/ui/base/test/cocoa_helper.h index a7665cd..4ec09b1 100644 --- a/ui/base/test/cocoa_helper.h +++ b/ui/base/test/cocoa_helper.h
@@ -18,8 +18,6 @@ // following ways: // - It allows -isKeyWindow to be manipulated to test things like focus rings // (which background windows won't normally display). -// - It ignores its real occlusion state and returns a value based on -// pretendIsOccluded. // - It ignores the system setting for full keyboard access and returns a value // based on pretendFullKeyboardAccessIsEnabled. @interface CocoaTestHelperWindow : NSWindow @@ -27,10 +25,6 @@ // Value to return for -isKeyWindow. @property(nonatomic) BOOL pretendIsKeyWindow; -// Value to return for -occlusionState. Setting posts a -// NSWindowDidChangeOcclusionStateNotification. -@property(nonatomic) BOOL pretendIsOccluded; - // Value to return for -isOnActiveSpace. Posts // NSWorkspaceActiveSpaceDidChangeNotification when set. @property(nonatomic) BOOL pretendIsOnActiveSpace; @@ -62,8 +56,6 @@ - (BOOL)isKeyWindow; -- (NSWindowOcclusionState)occlusionState; - @end namespace ui {
diff --git a/ui/base/test/cocoa_helper.mm b/ui/base/test/cocoa_helper.mm index 9311adc..96cc18dd 100644 --- a/ui/base/test/cocoa_helper.mm +++ b/ui/base/test/cocoa_helper.mm
@@ -32,7 +32,6 @@ @implementation CocoaTestHelperWindow @synthesize pretendIsKeyWindow = _pretendIsKeyWindow; -@synthesize pretendIsOccluded = _pretendIsOccluded; @synthesize pretendIsOnActiveSpace = _pretendIsOnActiveSpace; @synthesize pretendFullKeyboardAccessIsEnabled = _pretendFullKeyboardAccessIsEnabled; @@ -78,13 +77,6 @@ EXPECT_TRUE([self makeFirstResponder:NSApp]); } -- (void)setPretendIsOccluded:(BOOL)flag { - _pretendIsOccluded = flag; - [[NSNotificationCenter defaultCenter] - postNotificationName:NSWindowDidChangeOcclusionStateNotification - object:self]; -} - - (void)setPretendIsOnActiveSpace:(BOOL)pretendIsOnActiveSpace { _pretendIsOnActiveSpace = pretendIsOnActiveSpace; [[NSWorkspace sharedWorkspace].notificationCenter @@ -106,10 +98,6 @@ return _pretendFullKeyboardAccessIsEnabled; } -- (NSWindowOcclusionState)occlusionState { - return _pretendIsOccluded ? 0 : NSWindowOcclusionStateVisible; -} - - (NSArray<NSView*>*)validKeyViews { NSMutableArray<NSView*>* validKeyViews = [NSMutableArray array]; NSView* contentView = self.contentView;
diff --git a/ui/chromeos/ui_chromeos_strings.grd b/ui/chromeos/ui_chromeos_strings.grd index 1ef3611..824963e 100644 --- a/ui/chromeos/ui_chromeos_strings.grd +++ b/ui/chromeos/ui_chromeos_strings.grd
@@ -17,6 +17,7 @@ <output filename="ui_chromeos_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ui_chromeos_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ui_chromeos_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ui_chromeos_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ui_chromeos_strings_da.pak" type="data_package" lang="da" /> <output filename="ui_chromeos_strings_de.pak" type="data_package" lang="de" /> <output filename="ui_chromeos_strings_el.pak" type="data_package" lang="el" />
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc index c3e765f3..96dca421 100644 --- a/ui/events/ozone/evdev/event_device_info.cc +++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -74,6 +74,7 @@ {0x056e, 0x0141}, // Elecom EPRIM Blue LED 5 button mouse 228 {0x056e, 0x0159}, // Elecom Blue LED Mouse 203 {0x05e0, 0x1200}, // Zebra LS2208 barcode scanner + {0x0951, 0x1727}, // HyperX Pulsefire Haste Gaming Mouse {0x0c45, 0x7403}, // RDing FootSwitch1F1 {0x1038, 0x1369}, // SteelSeries Sensei RAW Frost Blue {0x1038, 0x1824}, // SteelSeries Rival 3 Wired
diff --git a/ui/strings/app_locale_settings.grd b/ui/strings/app_locale_settings.grd index d3b6f55..b318a20 100644 --- a/ui/strings/app_locale_settings.grd +++ b/ui/strings/app_locale_settings.grd
@@ -15,6 +15,7 @@ <output filename="app_locale_settings_bs.pak" type="data_package" lang="bs" /> <output filename="app_locale_settings_ca.pak" type="data_package" lang="ca" /> <output filename="app_locale_settings_cs.pak" type="data_package" lang="cs" /> + <output filename="app_locale_settings_cy.pak" type="data_package" lang="cy" /> <output filename="app_locale_settings_da.pak" type="data_package" lang="da" /> <output filename="app_locale_settings_de.pak" type="data_package" lang="de" /> <output filename="app_locale_settings_el.pak" type="data_package" lang="el" />
diff --git a/ui/strings/ax_strings.grd b/ui/strings/ax_strings.grd index 1a6701ee..a78176b 100644 --- a/ui/strings/ax_strings.grd +++ b/ui/strings/ax_strings.grd
@@ -21,6 +21,7 @@ <output filename="ax_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ax_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ax_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ax_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ax_strings_da.pak" type="data_package" lang="da" /> <output filename="ax_strings_de.pak" type="data_package" lang="de" /> <output filename="ax_strings_el.pak" type="data_package" lang="el" />
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 46a95c6..7b3e067 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -27,6 +27,7 @@ <output filename="ui_strings_bs.pak" type="data_package" lang="bs" /> <output filename="ui_strings_ca.pak" type="data_package" lang="ca" /> <output filename="ui_strings_cs.pak" type="data_package" lang="cs" /> + <output filename="ui_strings_cy.pak" type="data_package" lang="cy" /> <output filename="ui_strings_da.pak" type="data_package" lang="da" /> <output filename="ui_strings_de.pak" type="data_package" lang="de" /> <output filename="ui_strings_el.pak" type="data_package" lang="el" />
diff --git a/ui/webui/BUILD.gn b/ui/webui/BUILD.gn index cc37aa3..d0e3bf6 100644 --- a/ui/webui/BUILD.gn +++ b/ui/webui/BUILD.gn
@@ -16,10 +16,7 @@ "webui_allowlist.h", "webui_allowlist_provider.cc", "webui_allowlist_provider.h", - "webui_config.cc", "webui_config.h", - "webui_config_map.cc", - "webui_config_map.h", ] deps = [
diff --git a/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts b/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts index 810b2db5..9553765 100644 --- a/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts +++ b/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts
@@ -11,6 +11,16 @@ * @fileoverview */ +type CrA11yAnnouncerMessagesSentEvent = CustomEvent<{ + messages: string[], +}>; + +declare global { + interface HTMLElementEventMap { + 'cr-a11y-announcer-messages-sent': CrA11yAnnouncerMessagesSentEvent; + } +} + /** * 150ms seems to be around the minimum time required for screen readers to * read out consecutively queued messages. @@ -79,6 +89,12 @@ messagesDiv.appendChild(div); } + // Dispatch a custom event to allow consumers to know when certain alerts + // have been sent to the screen reader. + this.dispatchEvent(new CustomEvent( + 'cr-a11y-announcer-messages-sent', + {bubbles: true, detail: {messages: this.messages_.slice()}})); + this.messages_.length = 0; this.currentTimeout_ = null; }, TIMEOUT_MS);
diff --git a/ui/webui/untrusted_web_ui_controller_factory.h b/ui/webui/untrusted_web_ui_controller_factory.h index 8e14c260..f602b7c 100644 --- a/ui/webui/untrusted_web_ui_controller_factory.h +++ b/ui/webui/untrusted_web_ui_controller_factory.h
@@ -12,10 +12,10 @@ namespace content { class BrowserContext; class WebUIController; +class WebUIConfig; } // namespace content namespace ui { -class WebUIConfig; // Factory class for WebUIControllers for chrome-untrusted:// URLs. // @@ -41,13 +41,13 @@ protected: // Map of hosts to their corresponding WebUIConfigs. using WebUIConfigMap = - base::flat_map<std::string, std::unique_ptr<ui::WebUIConfig>>; + base::flat_map<std::string, std::unique_ptr<content::WebUIConfig>>; virtual const WebUIConfigMap& GetWebUIConfigMap() = 0; private: // Returns the WebUIConfig for |url| if it's registered and the WebUI is // enabled. (WebUIs can be disabled based on the profile or feature flags.) - ui::WebUIConfig* GetConfigIfWebUIEnabled( + content::WebUIConfig* GetConfigIfWebUIEnabled( content::BrowserContext* browser_context, const GURL& url); };
diff --git a/ui/webui/webui_config.h b/ui/webui/webui_config.h index 9664e1ff..ca13c2d 100644 --- a/ui/webui/webui_config.h +++ b/ui/webui/webui_config.h
@@ -5,45 +5,12 @@ #ifndef UI_WEBUI_WEBUI_CONFIG_H_ #define UI_WEBUI_WEBUI_CONFIG_H_ -#include <memory> -#include <string> - -#include "base/strings/string_piece.h" - -namespace content { -class BrowserContext; -class WebUIController; -class WebUI; -} // namespace content +#include "content/public/browser/webui_config.h" namespace ui { -// Class that stores properties for a WebUI. -class WebUIConfig { - public: - explicit WebUIConfig(base::StringPiece scheme, base::StringPiece host); - virtual ~WebUIConfig(); - WebUIConfig(const WebUIConfig&) = delete; - WebUIConfig& operator=(const WebUIConfig&) = delete; - - // Scheme for the WebUI. - const std::string& scheme() const { return scheme_; } - - // Host the WebUI serves. - const std::string& host() const { return host_; } - - // Returns whether the WebUI is enabled e.g. the necessary feature flags are - // on/off, the WebUI is enabled in incognito, etc. Defaults to true. - virtual bool IsWebUIEnabled(content::BrowserContext* browser_context); - - // Returns a WebUIController for the WebUI. - virtual std::unique_ptr<content::WebUIController> CreateWebUIController( - content::WebUI* web_ui) = 0; - - private: - const std::string scheme_; - const std::string host_; -}; +// TODO(ortuno): Remove once all users of WebUIConfig are migrated. +using content::WebUIConfig; } // namespace ui
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py index ca2f0c1..8fa31a2 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py +++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
@@ -40,7 +40,7 @@ self.file_name = os.path.basename(self.path_in_repo) current_dir = self.path_in_repo packages = [] - while current_dir is not '': + while current_dir != '': dir_name, base_name = os.path.split(current_dir) packages.append(base_name) if base_name == 'org':
diff --git a/weblayer/browser/verdict_cache_manager_factory.cc b/weblayer/browser/verdict_cache_manager_factory.cc index a6c25bb9..e63b37c 100644 --- a/weblayer/browser/verdict_cache_manager_factory.cc +++ b/weblayer/browser/verdict_cache_manager_factory.cc
@@ -37,9 +37,9 @@ content::BrowserContext* context) const { BrowserContextImpl* context_impl = static_cast<BrowserContextImpl*>(context); return new safe_browsing::VerdictCacheManager( - nullptr /* history service */, + /*history_service=*/nullptr, HostContentSettingsMapFactory::GetForBrowserContext(context), - context_impl->pref_service()); + context_impl->pref_service(), /*sync_observer=*/nullptr); } } // namespace weblayer
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationController.java b/weblayer/public/java/org/chromium/weblayer/NavigationController.java index 5298d6fa..ff3043f 100644 --- a/weblayer/public/java/org/chromium/weblayer/NavigationController.java +++ b/weblayer/public/java/org/chromium/weblayer/NavigationController.java
@@ -153,9 +153,8 @@ /** * Navigates to the entry at {@link index}. * - * @throws IndexOutOfBoundsException If index is not between 0 and {@link - * getNavigationListCurrentIndex}. - * @throws IndexOutOfBoundsException + * @throws IndexOutOfBoundsException If index is negative or is not less than {@link + * getNavigationListSize}. */ public void goToIndex(int index) throws IndexOutOfBoundsException { ThreadCheck.ensureOnUiThread(); @@ -223,8 +222,8 @@ * Returns the uri to display for the navigation at index. * * @param index The index of the navigation. - * @throws IndexOutOfBoundsException If index is not between 0 and {@link - * getNavigationListCurrentIndex}. + * @throws IndexOutOfBoundsException If index is negative or is not less than {@link + * getNavigationListSize}. */ @NonNull public Uri getNavigationEntryDisplayUri(int index) throws IndexOutOfBoundsException { @@ -240,8 +239,8 @@ /** * Returns the title of the navigation entry at the supplied index. * - * @throws IndexOutOfBoundsException If index is not between 0 and {@link - * getNavigationListCurrentIndex}. + * @throws IndexOutOfBoundsException If index is negative or is not less than {@link + * getNavigationListSize}. */ @NonNull public String getNavigationEntryTitle(int index) throws IndexOutOfBoundsException { @@ -259,8 +258,8 @@ * This will be true for certain navigations, such as certain client side redirects and * history.pushState navigations done without user interaction. * - * @throws IndexOutOfBoundsException If index is not between 0 and {@link - * getNavigationListCurrentIndex}. + * @throws IndexOutOfBoundsException If index is negative or is not less than {@link + * getNavigationListSize}. */ public boolean isNavigationEntrySkippable(int index) throws IndexOutOfBoundsException { ThreadCheck.ensureOnUiThread();