diff --git a/DEPS b/DEPS
index 35cbc013..16b94ad 100644
--- a/DEPS
+++ b/DEPS
@@ -195,11 +195,11 @@
   # 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': 'b82d9b5d3b64d220c34a89a8125420f317ab816d',
+  'skia_revision': '74a7a81b984c93e7a8682d5096ea674c40fac663',
   # 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': '26aefc721cb2bbc63e070796204183c53d93abd4',
+  'v8_revision': 'd6c02e4a7fc7051ff7d194041f222acf26fee1e5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -207,7 +207,7 @@
   # 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': '41442cce3d0f30dbfce4d95bdda18c0faa452b43',
+  'angle_revision': '382e698da1996ab3e086de6817ec175d6073f623',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -266,7 +266,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': 'f3a9afdfa19b5cafa890087b71760c63c736debf',
+  'devtools_frontend_revision': '6d143ae8af4efab8ad440d0e895aac01a62b4f5b',
   # 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.
@@ -318,7 +318,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '8c9858e9b8e36b8c13606b1053133ab395c03418',
+  'dawn_revision': 'eac38cfbc1dee9080a31350c43a538e9f0e8f372',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -890,7 +890,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'b582eea93ac1554fc88f2fc443f68080c1921012',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '94ebd189a1d513f1d37313e0875842a48554902f',
       'condition': 'checkout_linux',
   },
 
@@ -946,7 +946,7 @@
     Var('chromium_git') + '/codecs/libgav1.git' + '@' + 'e46493b9148e0d1e63f55b5890bff503822616e5',
 
   'src/third_party/glslang/src':
-    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '928b7b26bd73bcf020687a54e6a8c74052e1e7b2',
+    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '5743eed4d16757402517a1068137f4bc1645ee87',
 
   'src/third_party/google_toolbox_for_mac/src': {
       'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
@@ -1248,7 +1248,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'fce06b20005cdc2e98d266719088811c65eecf0f',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4b656a010be50665d73995d66c5f5a544262b10f',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1465,7 +1465,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '353dcec4c1e839753875ed515e106647dc241e39',
+    Var('webrtc_git') + '/src.git' + '@' + '6b7d25eed32d44380a93f5f2a71ce6dba94c59ca',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1537,7 +1537,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d134c7ab73b3f2c3afe32d5e04ddc6dcf6c3f1f2',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@981002aea991551f0f26639a5a8d3db42196881a',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index c2fabf06..67fa7f7 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1944,6 +1944,7 @@
     "system/message_center/ash_message_popup_collection_unittest.cc",
     "system/message_center/inactive_user_notification_blocker_unittest.cc",
     "system/message_center/message_center_ui_controller_unittest.cc",
+    "system/message_center/notification_swipe_control_view_unittest.cc",
     "system/message_center/notifier_settings_view_unittest.cc",
     "system/message_center/session_state_notification_blocker_unittest.cc",
     "system/message_center/unified_message_center_bubble_unittest.cc",
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 1e49114..7c3a873 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -5,10 +5,10 @@
 #include "ash/login/ui/login_password_view.h"
 
 #include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/login/ui/arrow_button_view.h"
 #include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
 #include "ash/login/ui/hover_notifier.h"
 #include "ash/login/ui/lock_screen.h"
-#include "ash/login/ui/login_button.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/public/cpp/login_constants.h"
 #include "ash/public/cpp/login_types.h"
@@ -16,6 +16,7 @@
 #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 "base/bind.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -35,6 +36,7 @@
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/controls/textfield/textfield.h"
@@ -57,8 +59,25 @@
 // Margin above/below the password view.
 constexpr const int kMarginAboveBelowPasswordIconsDp = 8;
 
-// Total width of the password view.
-constexpr int kPasswordTotalWidthDp = 204;
+// Spacing between the password textfield and the submit button.
+constexpr int kSpacingBetweenPasswordTextFieldAndSubmitButtonDp = 8;
+
+// Size (width/height) of the submit button.
+constexpr int kSubmitButtonSizeDp = 32;
+
+// Left padding of the password view allowing the view to have its center
+// aligned with the one of the user pod.
+constexpr int kLeftPaddingPasswordView =
+    kSubmitButtonSizeDp + kSpacingBetweenPasswordTextFieldAndSubmitButtonDp;
+
+// Width of the password textfield, placed at the center of the password view.
+constexpr int kPasswordTextfieldWidthDp = 204;
+
+// Total width of the password view (left margin + password textfield + spacing
+// + submit button).
+constexpr int kPasswordTotalWidthDp =
+    kLeftPaddingPasswordView + kPasswordTextfieldWidthDp + kSubmitButtonSizeDp +
+    kSpacingBetweenPasswordTextFieldAndSubmitButtonDp;
 
 // Delta between normal font and font of the typed text.
 constexpr int kPasswordFontDeltaSize = 5;
@@ -66,9 +85,6 @@
 // Spacing between glyphs.
 constexpr int kPasswordGlyphSpacing = 6;
 
-// Size (width/height) of the submit button.
-constexpr int kSubmitButtonSizeDp = 20;
-
 // Size (width/height) of the display password button.
 constexpr int kDisplayPasswordButtonSizeDp = 20;
 
@@ -458,12 +474,25 @@
       hide_password_timer_(std::make_unique<base::RetainingOneShotTimer>()) {
   Shell::Get()->ime_controller()->AddObserver(this);
 
+  // Contains the password layout on the left and the submit button on the
+  // right.
   auto* root_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kVertical));
+      views::BoxLayout::Orientation::kHorizontal,
+      gfx::Insets(0, kLeftPaddingPasswordView, 0, 0),
+      kSpacingBetweenPasswordTextFieldAndSubmitButtonDp));
   root_layout->set_main_axis_alignment(
-      views::BoxLayout::MainAxisAlignment::kCenter);
+      views::BoxLayout::MainAxisAlignment::kEnd);
 
-  password_row_ = AddChildView(std::make_unique<NonAccessibleView>());
+  // Contains the password row along with the separator.
+  auto* password = AddChildView(std::make_unique<views::View>());
+  std::unique_ptr<views::BoxLayout> password_layout =
+      std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical);
+  password_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
+  password->SetLayoutManager(std::move(password_layout));
+
+  password_row_ = password->AddChildView(std::make_unique<NonAccessibleView>());
   auto layout = std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal,
       gfx::Insets(kMarginAboveBelowPasswordIconsDp, 0));
@@ -511,29 +540,24 @@
   capslock_icon_->SetVisible(false);
 
   if (is_display_password_feature_enabled_) {
-    // Display password button.
     display_password_button_ = password_row_->AddChildView(
         std::make_unique<DisplayPasswordButton>(this));
-  } else {
-    // Submit button.
-    submit_button_ =
-        password_row_->AddChildView(std::make_unique<LoginButton>(this));
-    submit_button_->SetImage(
-        views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(kLockScreenArrowIcon, kSubmitButtonSizeDp,
-                              login_constants::kButtonEnabledColor));
-    submit_button_->SetImage(
-        views::Button::STATE_DISABLED,
-        gfx::CreateVectorIcon(
-            kLockScreenArrowIcon, kSubmitButtonSizeDp,
-            SkColorSetA(login_constants::kButtonEnabledColor,
-                        login_constants::kButtonDisabledAlpha)));
-    submit_button_->SetAccessibleName(
-        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SUBMIT_BUTTON_ACCESSIBLE_NAME));
   }
 
   // Separator on bottom.
-  separator_ = AddChildView(std::make_unique<NonAccessibleSeparator>());
+  separator_ =
+      password->AddChildView(std::make_unique<NonAccessibleSeparator>());
+
+  submit_button_ = AddChildView(std::make_unique<ArrowButtonView>(
+      /*listener=*/this, kSubmitButtonSizeDp));
+  const AshColorProvider* color_provider = AshColorProvider::Get();
+  SkColor color = color_provider->GetControlsLayerColor(
+      AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive,
+      AshColorProvider::AshColorMode::kDark);
+  submit_button_->SetBackgroundColor(color);
+  submit_button_->SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SUBMIT_BUTTON_ACCESSIBLE_NAME));
+  submit_button_->SetEnabled(false);
 
   // Initialize the capslock icon and the separator without a highlight.
   SetSeparatorAndCapsLockHighlighted(/*highlight=*/false);
@@ -692,12 +716,11 @@
 
 void LoginPasswordView::ButtonPressed(views::Button* sender,
                                       const ui::Event& event) {
-  if (is_display_password_feature_enabled_) {
+  if (sender == submit_button_) {
+    SubmitPassword();
+  } else if (is_display_password_feature_enabled_) {
     DCHECK_EQ(sender, display_password_button_);
     InvertPasswordDisplayingState();
-  } else {
-    DCHECK_EQ(sender, submit_button_);
-    SubmitPassword();
   }
 }
 
@@ -755,8 +778,7 @@
 }
 
 void LoginPasswordView::UpdateUiState() {
-  if (!is_display_password_feature_enabled_)
-    submit_button_->SetEnabled(IsPasswordSubmittable());
+  submit_button_->SetEnabled(IsPasswordSubmittable());
 }
 
 void LoginPasswordView::OnCapsLockChanged(bool enabled) {
diff --git a/ash/login/ui/login_password_view.h b/ash/login/ui/login_password_view.h
index d500aef..a7eda434 100644
--- a/ash/login/ui/login_password_view.h
+++ b/ash/login/ui/login_password_view.h
@@ -26,12 +26,12 @@
 }  // namespace views
 
 namespace ash {
-class LoginButton;
+class ArrowButtonView;
 enum class EasyUnlockIconId;
 
-// Contains a textfield instance with a submit button when the display password
-// button feature is disabled, and a display password button otherwise. The user
-// can type a password into the textfield and hit enter to submit.
+// Contains a textfield and a submit button. When the display password button
+// feature is enabled, the textfield contains a button in the form of an eye
+// icon that the user can click on to reveal the password.
 //
 // This view is always rendered via layers.
 //
@@ -39,18 +39,18 @@
 // When the display password button feature is disabled, the password view looks
 // like this:
 //
-// * * * * * *     =>
+// * * * * * *         (=>)
 // ------------------
 //
 // When the display password button feature is enabled, the password view looks
 // like this by default:
 //
-//  * * * * * *    (\)
+//  * * * * * *    (\)  (=>)
 //  ------------------
 //
 //  or this, in display mode:
 //
-//  1 2 3 4 5 6    (o)
+//  1 2 3 4 5 6    (o)  (=>)
 //  ------------------
 class ASH_EXPORT LoginPasswordView : public views::View,
                                      public views::ButtonListener,
@@ -208,7 +208,7 @@
   views::View* password_row_ = nullptr;
 
   LoginTextfield* textfield_ = nullptr;
-  LoginButton* submit_button_ = nullptr;
+  ArrowButtonView* submit_button_ = nullptr;
   DisplayPasswordButton* display_password_button_ = nullptr;
   views::ImageView* capslock_icon_ = nullptr;
   views::Separator* separator_ = nullptr;
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 403c4d1..a3914f3 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -140,19 +140,25 @@
 };
 
 // An animation metrics reporter for the shelf navigation widget.
-class ASH_EXPORT NavigationWidgetAnimationMetricsReporter {
+class ASH_EXPORT NavigationWidgetAnimationMetricsReporter
+    : public ShelfLayoutManagerObserver {
  public:
-  NavigationWidgetAnimationMetricsReporter() = default;
+  explicit NavigationWidgetAnimationMetricsReporter(Shelf* shelf)
+      : shelf_(shelf) {
+    shelf_->shelf_layout_manager()->AddObserver(this);
+  }
 
-  ~NavigationWidgetAnimationMetricsReporter() = default;
+  ~NavigationWidgetAnimationMetricsReporter() override {
+    shelf_->shelf_layout_manager()->RemoveObserver(this);
+  }
 
   NavigationWidgetAnimationMetricsReporter(
       const NavigationWidgetAnimationMetricsReporter&) = delete;
   NavigationWidgetAnimationMetricsReporter& operator=(
       const NavigationWidgetAnimationMetricsReporter&) = delete;
 
-  void ReportSmoothness(HotseatState target_hotseat_state, int smoothness) {
-    switch (target_hotseat_state) {
+  void ReportSmoothness(int smoothness) {
+    switch (target_state_) {
       case HotseatState::kShownClamshell:
       case HotseatState::kShownHomeLauncher:
         UMA_HISTOGRAM_PERCENTAGE(
@@ -178,15 +184,24 @@
     }
   }
 
-  metrics_util::ReportCallback GetReportCallback(
-      HotseatState target_hotseat_state) {
-    DCHECK_NE(target_hotseat_state, HotseatState::kNone);
+  metrics_util::ReportCallback GetReportCallback() {
     return metrics_util::ForSmoothness(base::BindRepeating(
         &NavigationWidgetAnimationMetricsReporter::ReportSmoothness,
-        weak_ptr_factory_.GetWeakPtr(), target_hotseat_state));
+        weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  // ShelfLayoutManagerObserver:
+  void OnHotseatStateChanged(HotseatState old_state,
+                             HotseatState new_state) override {
+    target_state_ = new_state;
   }
 
  private:
+  Shelf* const shelf_;
+
+  // The state to which the animation is transitioning.
+  HotseatState target_state_ = HotseatState::kShownHomeLauncher;
+
   base::WeakPtrFactory<NavigationWidgetAnimationMetricsReporter>
       weak_ptr_factory_{this};
 };
@@ -374,7 +389,7 @@
       this, hotseat_widget()->GetShelfView());
   navigation_widget_->Initialize(container);
   navigation_widget_metrics_reporter_ =
-      std::make_unique<NavigationWidgetAnimationMetricsReporter>();
+      std::make_unique<NavigationWidgetAnimationMetricsReporter>(this);
 }
 
 void Shelf::CreateHotseatWidget(aura::Window* container) {
@@ -670,10 +685,9 @@
       target_state);
 }
 
-metrics_util::ReportCallback Shelf::GetNavigationWidgetAnimationReportCallback(
-    HotseatState target_hotseat_state) {
-  return navigation_widget_metrics_reporter_->GetReportCallback(
-      target_hotseat_state);
+metrics_util::ReportCallback
+Shelf::GetNavigationWidgetAnimationReportCallback() {
+  return navigation_widget_metrics_reporter_->GetReportCallback();
 }
 
 void Shelf::WillDeleteShelfLayoutManager() {
diff --git a/ash/shelf/shelf.h b/ash/shelf/shelf.h
index ec33d84a..0fb0647 100644
--- a/ash/shelf/shelf.h
+++ b/ash/shelf/shelf.h
@@ -237,8 +237,7 @@
   metrics_util::ReportCallback GetTranslucentBackgroundReportCallback(
       HotseatState target_state);
 
-  metrics_util::ReportCallback GetNavigationWidgetAnimationReportCallback(
-      HotseatState target_hotseat_state);
+  metrics_util::ReportCallback GetNavigationWidgetAnimationReportCallback();
 
  protected:
   // ShelfLayoutManagerObserver:
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 1b73915..3606d23 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1318,7 +1318,7 @@
 
 HotseatState ShelfLayoutManager::CalculateHotseatState(
     ShelfVisibilityState visibility_state,
-    ShelfAutoHideState auto_hide_state) const {
+    ShelfAutoHideState auto_hide_state) {
   if (!IsHotseatEnabled() || !shelf_->IsHorizontalAlignment())
     return HotseatState::kShownClamshell;
 
@@ -1507,7 +1507,6 @@
     return false;
 
   dimmed_for_inactivity_ = dimmed;
-
   CalculateTargetBoundsAndUpdateWorkArea();
 
   const base::TimeDelta dim_animation_duration =
@@ -1520,7 +1519,7 @@
   if (animate) {
     navigation_widget_reporter.emplace(
         GetLayer(shelf_->navigation_widget())->GetAnimator(),
-        shelf_->GetNavigationWidgetAnimationReportCallback(hotseat_state()));
+        shelf_->GetNavigationWidgetAnimationReportCallback());
   }
 
   AnimateOpacity(GetLayer(shelf_->navigation_widget()), target_opacity_,
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 24ed5d8..2bcc0dd0 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -295,7 +295,7 @@
   // Overview, Shelf, and any active gestures.
   // TODO(manucornet): Move this to the hotseat class.
   HotseatState CalculateHotseatState(ShelfVisibilityState visibility_state,
-                                     ShelfAutoHideState auto_hide_state) const;
+                                     ShelfAutoHideState auto_hide_state);
 
  private:
   class UpdateShelfObserver;
diff --git a/ash/shelf/shelf_navigation_widget.cc b/ash/shelf/shelf_navigation_widget.cc
index 962e32f..e9b3659 100644
--- a/ash/shelf/shelf_navigation_widget.cc
+++ b/ash/shelf/shelf_navigation_widget.cc
@@ -145,7 +145,8 @@
 }  // namespace
 
 // An animation metrics reporter for the shelf navigation buttons.
-class ASH_EXPORT NavigationButtonAnimationMetricsReporter {
+class ASH_EXPORT NavigationButtonAnimationMetricsReporter
+    : public ShelfLayoutManagerObserver {
  public:
   // The different kinds of navigation buttons.
   enum class NavigationButtonType {
@@ -154,19 +155,24 @@
     // The Navigation Widget's home button.
     kHomeButton
   };
-  explicit NavigationButtonAnimationMetricsReporter(
+  NavigationButtonAnimationMetricsReporter(
+      Shelf* shelf,
       NavigationButtonType navigation_button_type)
-      : navigation_button_type_(navigation_button_type) {}
+      : shelf_(shelf), navigation_button_type_(navigation_button_type) {
+    shelf_->shelf_layout_manager()->AddObserver(this);
+  }
 
-  ~NavigationButtonAnimationMetricsReporter() = default;
+  ~NavigationButtonAnimationMetricsReporter() override {
+    shelf_->shelf_layout_manager()->RemoveObserver(this);
+  }
 
   NavigationButtonAnimationMetricsReporter(
       const NavigationButtonAnimationMetricsReporter&) = delete;
   NavigationButtonAnimationMetricsReporter& operator=(
       const NavigationButtonAnimationMetricsReporter&) = delete;
 
-  void ReportSmoothness(HotseatState target_hotseat_state, int smoothness) {
-    switch (target_hotseat_state) {
+  void ReportSmoothness(int smoothness) {
+    switch (target_state_) {
       case HotseatState::kShownClamshell:
       case HotseatState::kShownHomeLauncher:
         switch (navigation_button_type_) {
@@ -231,18 +237,28 @@
     }
   }
 
-  metrics_util::ReportCallback GetReportCallback(
-      HotseatState target_hotseat_state) {
-    DCHECK_NE(target_hotseat_state, HotseatState::kNone);
+  metrics_util::ReportCallback GetReportCallback() {
     return metrics_util::ForSmoothness(base::BindRepeating(
         &NavigationButtonAnimationMetricsReporter::ReportSmoothness,
-        weak_ptr_factory_.GetWeakPtr(), target_hotseat_state));
+        weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  // ShelfLayoutManagerObserver:
+  void OnHotseatStateChanged(HotseatState old_state,
+                             HotseatState new_state) override {
+    target_state_ = new_state;
   }
 
  private:
+  // Owned by RootWindowController
+  Shelf* const shelf_;
+
   // The type of navigation button that is animated.
   const NavigationButtonType navigation_button_type_;
 
+  // The state to which the animation is transitioning.
+  HotseatState target_state_ = HotseatState::kShownHomeLauncher;
+
   base::WeakPtrFactory<NavigationButtonAnimationMetricsReporter>
       weak_ptr_factory_{this};
 };
@@ -439,10 +455,12 @@
                                                   /*use_transforms=*/true)),
       back_button_metrics_reporter_(
           std::make_unique<NavigationButtonAnimationMetricsReporter>(
+              shelf,
               NavigationButtonAnimationMetricsReporter::NavigationButtonType::
                   kBackButton)),
       home_button_metrics_reporter_(
           std::make_unique<NavigationButtonAnimationMetricsReporter>(
+              shelf,
               NavigationButtonAnimationMetricsReporter::NavigationButtonType::
                   kHomeButton)) {
   DCHECK(shelf_);
@@ -577,10 +595,6 @@
       animate ? ShelfConfig::Get()->shelf_animation_duration()
               : base::TimeDelta::FromMilliseconds(0);
 
-  const HotseatState target_hotseat_state =
-      layout_manager->CalculateHotseatState(layout_manager->visibility_state(),
-                                            layout_manager->auto_hide_state());
-
   const bool update_opacity = !animate || GetLayer()->GetTargetOpacity() !=
                                               layout_manager->GetOpacity();
   const bool update_bounds =
@@ -597,8 +611,7 @@
     base::Optional<ui::AnimationThroughputReporter> reporter;
     if (animate) {
       reporter.emplace(nav_animation_setter.GetAnimator(),
-                       shelf_->GetNavigationWidgetAnimationReportCallback(
-                           target_hotseat_state));
+                       shelf_->GetNavigationWidgetAnimationReportCallback());
     }
     if (update_opacity)
       GetLayer()->SetOpacity(layout_manager->GetOpacity());
@@ -611,13 +624,11 @@
 
   views::View* const back_button = delegate_->back_button();
   UpdateButtonVisibility(back_button, back_button_shown, animate,
-                         back_button_metrics_reporter_.get(),
-                         target_hotseat_state);
+                         back_button_metrics_reporter_.get());
 
   views::View* const home_button = delegate_->home_button();
   UpdateButtonVisibility(home_button, home_button_shown, animate,
-                         home_button_metrics_reporter_.get(),
-                         target_hotseat_state);
+                         home_button_metrics_reporter_.get());
 
   if (back_button_shown) {
     // TODO(https://crbug.com/1058205): Test this behavior.
@@ -636,16 +647,13 @@
                         : GetFirstButtonBounds(shelf_->IsHorizontalAlignment());
 
   if (animate) {
-    if (bounds_animator_->GetTargetBounds(home_button) != home_button_bounds) {
-      bounds_animator_->SetAnimationDuration(animation_duration);
-      bounds_animator_->AnimateViewTo(
-          home_button, home_button_bounds,
-          std::make_unique<BoundsAnimationReporter>(
-              home_button, home_button_metrics_reporter_->GetReportCallback(
-                               target_hotseat_state)));
-    }
+    bounds_animator_->SetAnimationDuration(animation_duration);
+    bounds_animator_->AnimateViewTo(
+        home_button, home_button_bounds,
+        std::make_unique<BoundsAnimationReporter>(
+            home_button, home_button_metrics_reporter_->GetReportCallback()));
   } else {
-    bounds_animator_->Cancel();
+    bounds_animator_->StopAnimatingView(home_button);
     home_button->SetBoundsRect(home_button_bounds);
   }
 
@@ -675,8 +683,7 @@
     views::View* button,
     bool visible,
     bool animate,
-    NavigationButtonAnimationMetricsReporter* metrics_reporter,
-    HotseatState target_hotseat_state) {
+    NavigationButtonAnimationMetricsReporter* metrics_reporter) {
   if (animate && button->layer()->GetTargetOpacity() == visible)
     return;
 
@@ -698,7 +705,7 @@
   base::Optional<ui::AnimationThroughputReporter> reporter;
   if (animate) {
     reporter.emplace(opacity_settings.GetAnimator(),
-                     metrics_reporter->GetReportCallback(target_hotseat_state));
+                     metrics_reporter->GetReportCallback());
   }
 
   if (!visible)
diff --git a/ash/shelf/shelf_navigation_widget.h b/ash/shelf/shelf_navigation_widget.h
index d25943b..28a94d23 100644
--- a/ash/shelf/shelf_navigation_widget.h
+++ b/ash/shelf/shelf_navigation_widget.h
@@ -24,7 +24,6 @@
 namespace ash {
 class BackButton;
 class HomeButton;
-enum class HotseatState;
 class NavigationButtonAnimationMetricsReporter;
 class Shelf;
 class ShelfView;
@@ -99,8 +98,7 @@
       views::View* button,
       bool visible,
       bool animate,
-      NavigationButtonAnimationMetricsReporter* metrics_reporter,
-      HotseatState target_hotseat_state);
+      NavigationButtonAnimationMetricsReporter* metrics_reporter);
 
   // Returns the clip rectangle.
   gfx::Rect CalculateClipRect() const;
diff --git a/ash/shelf/shelf_view_test_api.cc b/ash/shelf/shelf_view_test_api.cc
index f3f3ac4..efbba3b 100644
--- a/ash/shelf/shelf_view_test_api.cc
+++ b/ash/shelf/shelf_view_test_api.cc
@@ -81,9 +81,6 @@
 
 void ShelfViewTestAPI::RunMessageLoopUntilAnimationsDone(
     views::BoundsAnimator* bounds_animator) {
-  if (!bounds_animator->IsAnimating())
-    return;
-
   std::unique_ptr<TestAPIAnimationObserver> observer(
       new TestAPIAnimationObserver());
 
diff --git a/ash/system/message_center/notification_swipe_control_view.cc b/ash/system/message_center/notification_swipe_control_view.cc
index 45e5d018..203ae61 100644
--- a/ash/system/message_center/notification_swipe_control_view.cc
+++ b/ash/system/message_center/notification_swipe_control_view.cc
@@ -185,17 +185,25 @@
 void NotificationSwipeControlView::ButtonPressed(views::Button* sender,
                                                  const ui::Event& event) {
   DCHECK(sender);
+  std::string notification_id = message_view_->notification_id();
+  auto weak_this = weak_factory_.GetWeakPtr();
+
   if (sender == settings_button_) {
     message_view_->OnSettingsButtonPressed(event);
-    metrics_utils::LogSettingsShown(message_view_->notification_id(),
+    metrics_utils::LogSettingsShown(notification_id,
                                     /*is_slide_controls=*/true,
                                     /*is_popup=*/false);
   } else if (sender == snooze_button_) {
     message_view_->OnSnoozeButtonPressed(event);
-    metrics_utils::LogSnoozed(message_view_->notification_id(),
+    metrics_utils::LogSnoozed(notification_id,
                               /*is_slide_controls=*/true,
                               /*is_popup=*/false);
   }
+
+  // Button handlers of |message_view_| may have closed |this|.
+  if (!weak_this)
+    return;
+
   HideButtons();
 
   // Closing the swipe control is done in these button pressed handlers.
diff --git a/ash/system/message_center/notification_swipe_control_view.h b/ash/system/message_center/notification_swipe_control_view.h
index 84bb0bc..d78f06bc 100644
--- a/ash/system/message_center/notification_swipe_control_view.h
+++ b/ash/system/message_center/notification_swipe_control_view.h
@@ -6,7 +6,7 @@
 #define ASH_SYSTEM_MESSAGE_CENTER_NOTIFICATION_SWIPE_CONTROL_VIEW_H_
 
 #include "ash/ash_export.h"
-#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -35,6 +35,9 @@
 
   explicit NotificationSwipeControlView(
       message_center::MessageView* message_view);
+  NotificationSwipeControlView(const NotificationSwipeControlView&) = delete;
+  NotificationSwipeControlView& operator=(const NotificationSwipeControlView&) =
+      delete;
   ~NotificationSwipeControlView() override;
 
   // views::View
@@ -50,6 +53,11 @@
   void UpdateCornerRadius(int top_radius, int bottom_radius);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(NotificationSwipeControlViewTest,
+                           DeleteOnSettingsButtonPressed);
+  FRIEND_TEST_ALL_PREFIXES(NotificationSwipeControlViewTest,
+                           DeleteOnSnoozeButtonPressed);
+
   // Change the visibility of the settings button.
   void ShowButtons(ButtonPosition button_position,
                    bool has_settings,
@@ -68,7 +76,7 @@
   views::ImageButton* settings_button_ = nullptr;
   views::ImageButton* snooze_button_ = nullptr;
 
-  DISALLOW_COPY_AND_ASSIGN(NotificationSwipeControlView);
+  base::WeakPtrFactory<NotificationSwipeControlView> weak_factory_{this};
 };
 
 }  // namespace ash
diff --git a/ash/system/message_center/notification_swipe_control_view_unittest.cc b/ash/system/message_center/notification_swipe_control_view_unittest.cc
new file mode 100644
index 0000000..813b7aa
--- /dev/null
+++ b/ash/system/message_center/notification_swipe_control_view_unittest.cc
@@ -0,0 +1,151 @@
+// 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 "ash/system/message_center/notification_swipe_control_view.h"
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/image/image.h"
+#include "ui/message_center/lock_screen/fake_lock_screen_controller.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/views/message_view.h"
+#include "ui/message_center/views/notification_control_buttons_view.h"
+#include "url/gurl.h"
+
+namespace {
+
+class MockMessageView : public message_center::MessageView {
+ public:
+  explicit MockMessageView(const message_center::Notification& notification)
+      : message_center::MessageView(notification),
+        buttons_view_(
+            std::make_unique<message_center::NotificationControlButtonsView>(
+                this)) {
+    buttons_view_->ShowSettingsButton(
+        notification.should_show_settings_button());
+    buttons_view_->ShowSnoozeButton(notification.should_show_snooze_button());
+  }
+  ~MockMessageView() override = default;
+
+  message_center::NotificationControlButtonsView* GetControlButtonsView()
+      const override {
+    return buttons_view_.get();
+  }
+
+  MOCK_METHOD(void,
+              OnSettingsButtonPressed,
+              (const ui::Event& event),
+              (override));
+  MOCK_METHOD(void,
+              OnSnoozeButtonPressed,
+              (const ui::Event& event),
+              (override));
+
+ private:
+  std::unique_ptr<message_center::NotificationControlButtonsView> buttons_view_;
+};
+
+}  // namespace
+
+namespace ash {
+
+class NotificationSwipeControlViewTest : public testing::Test {
+ public:
+  NotificationSwipeControlViewTest() = default;
+  ~NotificationSwipeControlViewTest() override = default;
+
+  void SetUp() override {
+    message_center::MessageCenter::Initialize(
+        std::make_unique<message_center::FakeLockScreenController>());
+
+    message_center::RichNotificationData rich_data;
+    rich_data.settings_button_handler =
+        message_center::SettingsButtonHandler::DELEGATE;
+    rich_data.should_show_snooze_button = true;
+    message_center::Notification notification(
+        message_center::NOTIFICATION_TYPE_SIMPLE, "id",
+        base::UTF8ToUTF16("title"), base::UTF8ToUTF16("id"), gfx::Image(),
+        base::string16(), GURL(),
+        message_center::NotifierId(message_center::NotifierType::APPLICATION,
+                                   "notifier_id"),
+        rich_data, nullptr);
+
+    message_view_ = std::make_unique<MockMessageView>(notification);
+  }
+
+  void TearDown() override { message_center::MessageCenter::Shutdown(); }
+
+ protected:
+  MockMessageView* message_view() { return message_view_.get(); }
+
+ private:
+  std::unique_ptr<MockMessageView> message_view_;
+};
+
+TEST_F(NotificationSwipeControlViewTest, DeleteOnSettingsButtonPressed) {
+  auto swipe_control_view =
+      std::make_unique<NotificationSwipeControlView>(message_view());
+
+  EXPECT_CALL(*message_view(), OnSettingsButtonPressed(testing::_))
+      .WillOnce(testing::DoDefault())
+      .WillOnce(
+          testing::InvokeWithoutArgs([&]() { swipe_control_view.reset(); }));
+
+  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::PointF(), gfx::PointF(),
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_NONE);
+
+  // First click will do nothing, expect that to work.
+  swipe_control_view->ShowButtons(
+      NotificationSwipeControlView::ButtonPosition::LEFT,
+      /*has_settings_button=*/true, /*has_snooze_button=*/true);
+  swipe_control_view->ButtonPressed(swipe_control_view->settings_button_,
+                                    press);
+  EXPECT_TRUE(swipe_control_view);
+
+  // Second click deletes |swipe_control_view| in the handler.
+  swipe_control_view->ShowButtons(
+      NotificationSwipeControlView::ButtonPosition::LEFT,
+      /*has_settings_button=*/true, /*has_snooze_button=*/true);
+  swipe_control_view->ButtonPressed(swipe_control_view->settings_button_,
+                                    press);
+  EXPECT_FALSE(swipe_control_view);
+}
+
+TEST_F(NotificationSwipeControlViewTest, DeleteOnSnoozeButtonPressed) {
+  auto swipe_control_view =
+      std::make_unique<NotificationSwipeControlView>(message_view());
+
+  EXPECT_CALL(*message_view(), OnSnoozeButtonPressed(testing::_))
+      .WillOnce(testing::DoDefault())
+      .WillOnce(
+          testing::InvokeWithoutArgs([&]() { swipe_control_view.reset(); }));
+
+  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::PointF(), gfx::PointF(),
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_NONE);
+
+  // First click will do nothing, expect that to work.
+  swipe_control_view->ShowButtons(
+      NotificationSwipeControlView::ButtonPosition::LEFT,
+      /*has_settings_button=*/true, /*has_snooze_button=*/true);
+  swipe_control_view->ButtonPressed(swipe_control_view->snooze_button_, press);
+  EXPECT_TRUE(swipe_control_view);
+
+  // Second click deletes |swipe_control_view| in the handler.
+  swipe_control_view->ShowButtons(
+      NotificationSwipeControlView::ButtonPosition::LEFT,
+      /*has_settings_button=*/true, /*has_snooze_button=*/true);
+  swipe_control_view->ButtonPressed(swipe_control_view->snooze_button_, press);
+  EXPECT_FALSE(swipe_control_view);
+}
+
+}  // namespace ash
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index 24aab8f..8b5e2745 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -19,14 +19,14 @@
 using base::allocator::AllocatorDispatch;
 
 void* PartitionMalloc(const AllocatorDispatch*, size_t size, void* context) {
-  return Allocator().Alloc(size, "");
+  return Allocator().AllocFlagsNoHooks(0, size);
 }
 
 void* PartitionCalloc(const AllocatorDispatch*,
                       size_t n,
                       size_t size,
                       void* context) {
-  return Allocator().AllocFlags(base::PartitionAllocZeroFill, n * size, "");
+  return Allocator().AllocFlagsNoHooks(base::PartitionAllocZeroFill, n * size);
 }
 
 void* PartitionMemalign(const AllocatorDispatch*,
@@ -35,18 +35,20 @@
                         void* context) {
   static base::NoDestructor<base::ThreadSafePartitionRoot> aligned_allocator{
       true /* enforce_alignment */};
-  return aligned_allocator->AlignedAlloc(alignment, size);
+  return aligned_allocator->AlignedAllocFlags(base::PartitionAllocNoHooks,
+                                              alignment, size);
 }
 
 void* PartitionRealloc(const AllocatorDispatch*,
                        void* address,
                        size_t size,
                        void* context) {
-  return Allocator().Realloc(address, size, "");
+  return Allocator().ReallocFlags(base::PartitionAllocNoHooks, address, size,
+                                  "");
 }
 
 void PartitionFree(const AllocatorDispatch*, void* address, void* context) {
-  base::ThreadSafePartitionRoot::Free(address);
+  base::ThreadSafePartitionRoot::FreeNoHooks(address);
 }
 
 size_t PartitionGetSizeEstimate(const AllocatorDispatch*,
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 00e573b..51c86e84 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -385,8 +385,12 @@
   PA_CHECK(result || flags & PartitionAllocReturnNull);
   return result;
 #else
-  if (UNLIKELY(!ptr))
-    return AllocFlags(flags, new_size, type_name);
+  bool no_hooks = flags & PartitionAllocNoHooks;
+  if (UNLIKELY(!ptr)) {
+    return no_hooks ? AllocFlagsNoHooks(flags, new_size)
+                    : AllocFlags(flags, new_size, type_name);
+  }
+
   if (UNLIKELY(!new_size)) {
     Free(ptr);
     return nullptr;
@@ -401,7 +405,7 @@
   const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
   bool overridden = false;
   size_t actual_old_size;
-  if (UNLIKELY(hooks_enabled)) {
+  if (UNLIKELY(!no_hooks && hooks_enabled)) {
     overridden = PartitionAllocHooks::ReallocOverrideHookIfEnabled(
         &actual_old_size, ptr);
   }
@@ -422,7 +426,7 @@
       }
     }
     if (success) {
-      if (UNLIKELY(hooks_enabled)) {
+      if (UNLIKELY(!no_hooks && hooks_enabled)) {
         PartitionAllocHooks::ReallocObserverHookIfEnabled(ptr, ptr, new_size,
                                                           type_name);
       }
@@ -454,7 +458,8 @@
   }
 
   // This realloc cannot be resized in-place. Sadness.
-  void* ret = AllocFlags(flags, new_size, type_name);
+  void* ret = no_hooks ? AllocFlagsNoHooks(flags, new_size)
+                       : AllocFlags(flags, new_size, type_name);
   if (!ret) {
     if (flags & PartitionAllocReturnNull)
       return nullptr;
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index 7d5fada..6e29e06 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -470,10 +470,22 @@
   // padding, and can be passed to |Free()| later.
   //
   // NOTE: Doesn't work when DCHECK_IS_ON(), as it is incompatible with cookies.
-  ALWAYS_INLINE void* AlignedAlloc(size_t alignment, size_t size);
+  ALWAYS_INLINE void* AlignedAllocFlags(int flags,
+                                        size_t alignment,
+                                        size_t size);
 
   ALWAYS_INLINE void* Alloc(size_t size, const char* type_name);
   ALWAYS_INLINE void* AllocFlags(int flags, size_t size, const char* type_name);
+  // Same as |AllocFlags()|, but bypasses the allocator hooks.
+  //
+  // This is separate from AllocFlags() because other callers of AllocFlags()
+  // should not have the extra branch checking whether the hooks should be
+  // ignored or not. This is the same reason why |FreeNoHooks()|
+  // exists. However, |AlignedAlloc()| and |Realloc()| have few callers, so
+  // taking the extra branch in the non-malloc() case doesn't hurt. In addition,
+  // for the malloc() case, the compiler correctly removes the branch, since
+  // this is marked |ALWAYS_INLINE|.
+  ALWAYS_INLINE void* AllocFlagsNoHooks(int flags, size_t size);
 
   ALWAYS_INLINE void* Realloc(void* ptr,
                               size_t new_size,
@@ -488,6 +500,8 @@
                               size_t new_size,
                               const char* type_name);
   ALWAYS_INLINE static void Free(void* ptr);
+  // Same as |Free()|, bypasses the allocator hooks.
+  ALWAYS_INLINE static void FreeNoHooks(void* ptr);
 
   ALWAYS_INLINE static size_t GetSizeFromPointer(void* ptr);
   ALWAYS_INLINE size_t GetSize(void* ptr) const;
@@ -587,10 +601,7 @@
               (page->bucket->is_direct_mapped() &&
                (bucket == Bucket::get_sentinel_bucket())));
 
-    if (UNLIKELY(page->get_raw_size_ptr())) {  // has raw size.
-      PA_DCHECK(page->get_raw_size() == size);
-      *allocated_size = size;
-    }
+    *allocated_size = page->GetAllocatedSize();
   }
 
   return ret;
@@ -610,32 +621,65 @@
     if (PartitionAllocHooks::FreeOverrideHookIfEnabled(ptr))
       return;
   }
+
+  FreeNoHooks(ptr);
+#endif  // defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+}
+
+// static
+template <bool thread_safe>
+ALWAYS_INLINE void PartitionRoot<thread_safe>::FreeNoHooks(void* ptr) {
+  if (UNLIKELY(!ptr))
+    return;
+
   // No check as the pointer hasn't been adjusted yet.
   Page* page = Page::FromPointerNoAlignmentCheck(ptr);
   // TODO(palmer): See if we can afford to make this a CHECK.
   PA_DCHECK(IsValidPage(page));
   auto* root = PartitionRoot<thread_safe>::FromPage(page);
-  if (root->allow_extras && !page->bucket->is_direct_mapped()) {
-    // Allocated size can be:
-    // - The slot size for small buckets, up to single-slot buckets.
-    // - Stored exactly, for single-slot buckets and direct-mapped allocations.
-    size_t allocated_size = page->get_raw_size();
-    PA_DCHECK(!allocated_size || page->bucket->slot_size >= allocated_size);
-    if (!allocated_size)
-      allocated_size = page->bucket->slot_size;
 
-    size_t size_with_no_extras =
-        internal::PartitionSizeAdjustSubtract(true, allocated_size);
-#if ENABLE_TAG_FOR_MTE_CHECKED_PTR && MTE_CHECKED_PTR_SET_TAG_AT_FREE
-    internal::PartitionTagIncrementValue(ptr, size_with_no_extras);
-#else
-    internal::PartitionTagClearValue(ptr, size_with_no_extras);
+  if (root->allow_extras) {
+    size_t allocated_size = page->GetAllocatedSize();
+
+    // |ptr| points after the tag and the cookie.
+    // The layout is | tag | cookie | data | cookie |
+    //               ^              ^
+    //               |             ptr
+    //      allocation_start_ptr
+    //
+    // Note: tag and cookie can be 0-sized.
+    void* allocation_start_ptr =
+        internal::PartitionPointerAdjustSubtract(true /* allow_extras */, ptr);
+
+#if DCHECK_IS_ON()
+    void* start_cookie_ptr =
+        internal::PartitionCookiePointerAdjustSubtract(ptr);
+    void* end_cookie_ptr = internal::PartitionCookiePointerAdjustSubtract(
+        reinterpret_cast<char*>(allocation_start_ptr) + allocated_size);
+
+    // If these asserts fire, you probably corrupted memory.
+    internal::PartitionCookieCheckValue(start_cookie_ptr);
+    internal::PartitionCookieCheckValue(end_cookie_ptr);
 #endif
+
+    if (!page->bucket->is_direct_mapped()) {
+      size_t size_with_no_extras =
+          internal::PartitionSizeAdjustSubtract(true, allocated_size);
+#if ENABLE_TAG_FOR_MTE_CHECKED_PTR && MTE_CHECKED_PTR_SET_TAG_AT_FREE
+      internal::PartitionTagIncrementValue(ptr, size_with_no_extras);
+#else
+      internal::PartitionTagClearValue(ptr, size_with_no_extras);
+#endif
+    }
+
+    ptr = allocation_start_ptr;
   }
-  ptr = internal::PartitionPointerAdjustSubtract(root->allow_extras, ptr);
+
+#if DCHECK_IS_ON()
+  memset(ptr, kFreedByte, page->GetAllocatedSize());
+#endif
 
   root->RawFree(ptr, page);
-#endif
 }
 
 template <bool thread_safe>
@@ -810,6 +854,8 @@
     size_t size,
     const char* type_name) {
   PA_DCHECK(flags < PartitionAllocLastFlag << 1);
+  PA_DCHECK((flags & PartitionAllocNoHooks) == 0);  // Internal only.
+  PA_DCHECK(initialized);
 
 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
   CHECK_MAX_SIZE_OR_RETURN_NULLPTR(size, flags);
@@ -829,13 +875,27 @@
       return ret;
     }
   }
+
+  ret = AllocFlagsNoHooks(flags, size);
+
+  if (UNLIKELY(hooks_enabled)) {
+    PartitionAllocHooks::AllocationObserverHookIfEnabled(ret, size, type_name);
+  }
+
+  return ret;
+#endif  // defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+}
+
+template <bool thread_safe>
+ALWAYS_INLINE void* PartitionRoot<thread_safe>::AllocFlagsNoHooks(int flags,
+                                                                  size_t size) {
   size_t requested_size = size;
   size = internal::PartitionSizeAdjustAdd(allow_extras, size);
   PA_CHECK(size >= requested_size);  // check for overflows
 
   size_t allocated_size;
   bool is_already_zeroed;
-  ret = RawAlloc(flags, size, &allocated_size, &is_already_zeroed);
+  void* ret = RawAlloc(flags, size, &allocated_size, &is_already_zeroed);
   if (UNLIKELY(!ret))
     return nullptr;
 
@@ -886,15 +946,8 @@
     internal::PartitionTagSetValue(ret, slot_size_with_no_extras,
                                    GetNewPartitionTag());
   }
-#endif
-
-  if (UNLIKELY(hooks_enabled)) {
-    PartitionAllocHooks::AllocationObserverHookIfEnabled(ret, requested_size,
-                                                         type_name);
-  }
-
+#endif  // !ENABLE_TAG_FOR_MTE_CHECKED_PTR || !MTE_CHECKED_PTR_SET_TAG_AT_FREE
   return ret;
-#endif
 }
 
 template <bool thread_safe>
@@ -914,31 +967,38 @@
 }
 
 template <bool thread_safe>
-ALWAYS_INLINE void* PartitionRoot<thread_safe>::AlignedAlloc(size_t alignment,
-                                                             size_t size) {
+ALWAYS_INLINE void* PartitionRoot<thread_safe>::AlignedAllocFlags(
+    int flags,
+    size_t alignment,
+    size_t size) {
   // Aligned allocation support relies on the natural alignment guarantees of
   // PartitionAlloc. Since cookies and tags are layered on top of
   // PartitionAlloc, they change the guarantees. As a consequence, forbid both.
   PA_DCHECK(!allow_extras);
+
   // This is mandated by |posix_memalign()|, so should never fire.
   PA_CHECK(base::bits::IsPowerOfTwo(alignment));
 
-  void* ptr;
+  size_t requested_size;
   // Handle cases such as size = 16, alignment = 64.
   // Wastes memory when a large alignment is requested with a small size, but
   // this is hard to avoid, and should not be too common.
   if (UNLIKELY(size < alignment)) {
-    ptr = Alloc(alignment, "");
+    requested_size = alignment;
   } else {
     // PartitionAlloc only guarantees alignment for power-of-two sized
     // allocations. To make sure this applies here, round up the allocation
     // size.
-    size_t size_rounded_up =
+    requested_size =
         static_cast<size_t>(1)
         << (sizeof(size_t) * 8 - base::bits::CountLeadingZeroBits(size - 1));
-    ptr = Alloc(size_rounded_up, "");
   }
 
+  PA_CHECK(requested_size >= size);  // Overflow check.
+  bool no_hooks = flags & PartitionAllocNoHooks;
+  void* ptr = no_hooks ? AllocFlagsNoHooks(0, requested_size)
+                       : Alloc(requested_size, "");
+
   // |alignment| is a power of two, but the compiler doesn't necessarily know
   // that. A regular % operation is very slow, make sure to use the equivalent,
   // faster form.
diff --git a/base/allocator/partition_allocator/partition_alloc_constants.h b/base/allocator/partition_allocator/partition_alloc_constants.h
index b1f97a3..242bddf1 100644
--- a/base/allocator/partition_allocator/partition_alloc_constants.h
+++ b/base/allocator/partition_allocator/partition_alloc_constants.h
@@ -176,8 +176,13 @@
     ((kNumBucketsPerOrder - 1) * kMaxBucketSpacing);
 // Limit when downsizing a direct mapping using `realloc`:
 static const size_t kMinDirectMappedDownsize = kMaxBucketed + 1;
-static const size_t kMaxDirectMapped =
-    (1UL << 31) + kPageAllocationGranularity;  // 2 GiB plus 1 more page.
+// Intentionally set to less than 2GiB to make sure that a 2GiB allocation
+// fails. This is a security choice in Chrome, to help making size_t vs int bugs
+// harder to exploit.
+//
+// There are matching limits in other allocators, such as tcmalloc. See
+// crbug.com/998048 for details.
+static const size_t kMaxDirectMapped = (1UL << 31) - kPageAllocationGranularity;
 static const size_t kBitsPerSizeT = sizeof(void*) * CHAR_BIT;
 
 // Constant for the memory reclaim logic.
@@ -198,8 +203,9 @@
 enum PartitionAllocFlags {
   PartitionAllocReturnNull = 1 << 0,
   PartitionAllocZeroFill = 1 << 1,
+  PartitionAllocNoHooks = 1 << 2,  // Internal only.
 
-  PartitionAllocLastFlag = PartitionAllocZeroFill
+  PartitionAllocLastFlag = PartitionAllocNoHooks
 };
 
 }  // namespace base
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 2bcb638..365ce1b 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -2478,7 +2478,8 @@
 
   for (size_t alloc_size : alloc_sizes) {
     for (size_t alignment : alignemnts) {
-      void* ptr = aligned_allocator.root()->AlignedAlloc(alignment, alloc_size);
+      void* ptr =
+          aligned_allocator.root()->AlignedAllocFlags(0, alignment, alloc_size);
       ASSERT_TRUE(ptr);
       EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % alignment, 0ull);
       allocator.root()->Free(ptr);
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index b5e7f0c..48def92 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -11,7 +11,6 @@
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_bucket.h"
-#include "base/allocator/partition_allocator/partition_cookie.h"
 #include "base/allocator/partition_allocator/partition_freelist_entry.h"
 #include "base/allocator/partition_allocator/partition_tag.h"
 #include "base/allocator/partition_allocator/random.h"
@@ -94,6 +93,21 @@
   ALWAYS_INLINE static PartitionPage* FromPointerNoAlignmentCheck(void* ptr);
   ALWAYS_INLINE static PartitionPage* FromPointer(void* ptr);
 
+  // Returns either the exact allocated size for direct-mapped and single-slot
+  // buckets, or the slot size. The second one is an overestimate of the real
+  // allocated size.
+  ALWAYS_INLINE size_t GetAllocatedSize() const {
+    // Allocated size can be:
+    // - The slot size for small enough buckets.
+    // - Stored exactly, for large buckets (see get_raw_size_ptr()), and
+    //   direct-mapped allocations.
+    size_t result = bucket->slot_size;
+    if (UNLIKELY(get_raw_size_ptr()))  // has row size.
+      result = get_raw_size();
+
+    return result;
+  }
+
   ALWAYS_INLINE const size_t* get_raw_size_ptr() const;
   ALWAYS_INLINE size_t* get_raw_size_ptr() {
     return const_cast<size_t*>(
@@ -216,10 +230,11 @@
 template <bool thread_safe>
 ALWAYS_INLINE const size_t* PartitionPage<thread_safe>::get_raw_size_ptr()
     const {
-  // For single-slot buckets which span more than one partition page, we
-  // have some spare metadata space to store the raw allocation size. We
-  // can use this to report better statistics.
-  if (bucket->slot_size <= kMaxSystemPagesPerSlotSpan * kSystemPageSize)
+  // For single-slot buckets which span more than
+  // |kMaxPartitionPagesPerSlotSpan| partition pages, we have some spare
+  // metadata space to store the raw allocation size. We can use this to report
+  // better statistics.
+  if (LIKELY(bucket->slot_size <= kMaxSystemPagesPerSlotSpan * kSystemPageSize))
     return nullptr;
 
   PA_DCHECK((bucket->slot_size % kSystemPageSize) == 0);
@@ -242,22 +257,6 @@
 #if DCHECK_IS_ON()
   auto* root = PartitionRoot<thread_safe>::FromPage(this);
   root->lock_.AssertAcquired();
-
-  size_t slot_size = bucket->slot_size;
-  const size_t raw_size = get_raw_size();
-  if (raw_size) {
-    slot_size = raw_size;
-  }
-
-  // If these asserts fire, you probably corrupted memory.
-  if (root->allow_extras) {
-    PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) +
-                              kInSlotTagBufferSize);
-    PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + slot_size -
-                              kCookieSize);
-  }
-
-  memset(ptr, kFreedByte, slot_size);
 #endif
 
   PA_DCHECK(num_allocated_slots);
diff --git a/base/process/memory.cc b/base/process/memory.cc
index 193c04b4..4454e32 100644
--- a/base/process/memory.cc
+++ b/base/process/memory.cc
@@ -6,10 +6,13 @@
 
 #if defined(OS_WIN)
 #include <windows.h>
+#else
+#include <unistd.h>
 #endif  // defined(OS_WIN)
 
 #include <string.h>
 
+#include "base/allocator/buildflags.h"
 #include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/partition_alloc_buildflags.h"
@@ -37,7 +40,15 @@
 #else
   size_t tmp_size = size;
   base::debug::Alias(&tmp_size);
-  LOG(FATAL) << "Out of memory. size=" << tmp_size;
+
+  // Note: Don't add anything that may allocate here. Depending on the
+  // allocator, this may be called from within the allocator (e.g. with
+  // PartitionAlloc), and would deadlock as our locks are not recursive.
+  //
+  // Additionally, this is unlikely to work, since allocating from an OOM
+  // handler is likely to fail.
+  abort();  // SIGABRT cannot really be caught, this will always _exit().
+
 #endif  // defined(OS_WIN)
 }
 
diff --git a/base/process/memory.h b/base/process/memory.h
index 1e3ebf7..0e0cc5b 100644
--- a/base/process/memory.h
+++ b/base/process/memory.h
@@ -64,6 +64,8 @@
 
 // Handles out of memory, with the failed allocation |size|, or 0 when it is not
 // known.
+//
+// Must be allocation-safe.
 BASE_EXPORT NOINLINE void OnNoMemoryInternal(size_t size);
 
 }  // namespace internal
diff --git a/base/process/memory_linux.cc b/base/process/memory_linux.cc
index ac8ffe1..9b854004 100644
--- a/base/process/memory_linux.cc
+++ b/base/process/memory_linux.cc
@@ -130,7 +130,24 @@
 
 bool UncheckedMalloc(size_t size, void** result) {
 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
+
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) || defined(OS_ANDROID)
+  // There are multiple reasons for not calling |UncheckedAlloc()| with
+  // PartitionAlloc:
+  //
+  // TODO(crbug.com/1111331) allocator::UncheckedMalloc() will not work anyway,
+  //   since the right flag is not passed to it.
+  //
+  // TODO(crbug.com/1111332) On Android, not all callers of UncheckedMalloc()
+  //   have the proper wrapping of symbols. As a consequence, using
+  //   UncheckedAlloc() leads to allocating and freeing with different
+  //   allocators. Deferring to malloc() makes sure that the same allocator is
+  //   used.
+  *result = malloc(size);
+#else
   *result = allocator::UncheckedAlloc(size);
+#endif
+
 #elif defined(MEMORY_TOOL_REPLACES_ALLOCATOR) || \
     (!defined(LIBC_GLIBC) && !BUILDFLAG(USE_TCMALLOC))
   *result = malloc(size);
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc
index d471f531..997dc9b 100644
--- a/base/process/memory_unittest.cc
+++ b/base/process/memory_unittest.cc
@@ -31,6 +31,7 @@
 #include <malloc/malloc.h>
 #include "base/allocator/allocator_interception_mac.h"
 #include "base/allocator/allocator_shim.h"
+#include "base/allocator/buildflags.h"
 #include "base/process/memory_unittest_mac.h"
 #endif
 #if defined(OS_LINUX)
@@ -105,20 +106,23 @@
 
 // OpenBSD does not support these tests. Don't test these on ASan/TSan/MSan
 // configurations: only test the real allocator.
-// Windows only supports these tests with the allocator shim in place.
 #if !defined(OS_OPENBSD) && BUILDFLAG(USE_ALLOCATOR_SHIM) && \
     !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
 
 namespace {
 #if defined(OS_WIN)
-// Windows raises an exception rather than using LOG(FATAL) in order to make the
-// exit code unique to OOM.
-const char* kOomRegex = "";
-const int kExitCode = base::win::kOomExceptionCode;
+
+// Windows raises an exception in order to make the exit code unique to OOM.
+#define ASSERT_OOM_DEATH(statement) \
+  ASSERT_EXIT(statement,            \
+              testing::ExitedWithCode(base::win::kOomExceptionCode), "")
+
 #else
-const char* kOomRegex = "Out of memory";
-const int kExitCode = 1;
-#endif
+
+#define ASSERT_OOM_DEATH(statement) ASSERT_DEATH(statement, "")
+
+#endif  // defined(OS_WIN)
+
 }  // namespace
 
 class OutOfMemoryTest : public testing::Test {
@@ -163,54 +167,54 @@
 };
 
 TEST_F(OutOfMemoryDeathTest, New) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = operator new(test_size_);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = operator new(test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, NewArray) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = new char[test_size_];
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = new char[test_size_];
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, Malloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = malloc(test_size_);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc(test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, Realloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = realloc(nullptr, test_size_);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = realloc(nullptr, test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, Calloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = calloc(1024, test_size_ / 1024L);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = calloc(1024, test_size_ / 1024L);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, AlignedAlloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = base::AlignedAlloc(test_size_, 8);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = base::AlignedAlloc(test_size_, 8);
+  });
 }
 
 // POSIX does not define an aligned realloc function.
 #if defined(OS_WIN)
 TEST_F(OutOfMemoryDeathTest, AlignedRealloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = _aligned_realloc(NULL, test_size_, 8);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = _aligned_realloc(nullptr, test_size_, 8);
+  });
 }
 
 namespace {
@@ -233,7 +237,7 @@
         SetUnhandledExceptionFilter(&ExitingUnhandledExceptionFilter);
         value_ = new char[test_size_];
       },
-      testing::ExitedWithCode(kUnhandledExceptionExitCode), kOomRegex);
+      testing::ExitedWithCode(kUnhandledExceptionExitCode), "");
 }
 #endif  // defined(OS_WIN)
 
@@ -241,54 +245,54 @@
 // See https://crbug.com/169327.
 #if !defined(OS_MAC) && !defined(OS_ANDROID)
 TEST_F(OutOfMemoryDeathTest, SecurityNew) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = operator new(insecure_test_size_);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = operator new(insecure_test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityNewArray) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = new char[insecure_test_size_];
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = new char[insecure_test_size_];
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityMalloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = malloc(insecure_test_size_);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc(insecure_test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityRealloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = realloc(nullptr, insecure_test_size_);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = realloc(nullptr, insecure_test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityCalloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = calloc(1024, insecure_test_size_ / 1024L);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = calloc(1024, insecure_test_size_ / 1024L);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityAlignedAlloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = base::AlignedAlloc(insecure_test_size_, 8);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = base::AlignedAlloc(insecure_test_size_, 8);
+  });
 }
 
 // POSIX does not define an aligned realloc function.
 #if defined(OS_WIN)
 TEST_F(OutOfMemoryDeathTest, SecurityAlignedRealloc) {
-  ASSERT_EXIT({
-      SetUpInDeathAssert();
-      value_ = _aligned_realloc(NULL, insecure_test_size_, 8);
-    }, testing::ExitedWithCode(kExitCode), kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = _aligned_realloc(nullptr, insecure_test_size_, 8);
+  });
 }
 #endif  // defined(OS_WIN)
 #endif  // !defined(OS_MAC) && !defined(OS_ANDROID)
@@ -296,47 +300,48 @@
 #if defined(OS_LINUX)
 
 TEST_F(OutOfMemoryDeathTest, Valloc) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = valloc(test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = valloc(test_size_);
+    EXPECT_TRUE(value_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityValloc) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = valloc(insecure_test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = valloc(insecure_test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, Pvalloc) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = pvalloc(test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = pvalloc(test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, SecurityPvalloc) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = pvalloc(insecure_test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = pvalloc(insecure_test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, Memalign) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = memalign(4, test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = memalign(4, test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
   // This tests that the run-time symbol resolution is overriding malloc for
   // shared libraries as well as for our code.
-  ASSERT_DEATH({
+  ASSERT_OOM_DEATH({
     SetUpInDeathAssert();
     value_ = MallocWrapper(test_size_);
-  }, kOomRegex);
+  });
 }
 #endif  // OS_LINUX
 
@@ -346,10 +351,10 @@
   // Grab the return value of posix_memalign to silence a compiler warning
   // about unused return values. We don't actually care about the return
   // value, since we're asserting death.
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
+  });
 }
 #endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
 
@@ -359,42 +364,42 @@
 
 TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
   malloc_zone_t* zone = malloc_default_purgeable_zone();
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = malloc_zone_malloc(zone, test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc_zone_malloc(zone, test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
   malloc_zone_t* zone = malloc_default_purgeable_zone();
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = malloc_zone_realloc(zone, NULL, test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc_zone_realloc(zone, nullptr, test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
   malloc_zone_t* zone = malloc_default_purgeable_zone();
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
   malloc_zone_t* zone = malloc_default_purgeable_zone();
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = malloc_zone_valloc(zone, test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc_zone_valloc(zone, test_size_);
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
   malloc_zone_t* zone = malloc_default_purgeable_zone();
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      value_ = malloc_zone_memalign(zone, 8, test_size_);
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    value_ = malloc_zone_memalign(zone, 8, test_size_);
+  });
 }
 
 // Since these allocation functions take a signed size, it's possible that
@@ -405,27 +410,29 @@
 // amount of (virtual) memory.
 
 TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      while ((value_ =
-              base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    while ((value_ =
+                base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {
+    }
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      while ((value_ =
-              base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    while ((value_ = base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {
+    }
+  });
 }
 
 TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      while ((value_ =
-              base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    while (
+        (value_ = base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {
+    }
+  });
 }
 
 #if !defined(ARCH_CPU_64_BITS)
@@ -434,10 +441,11 @@
 // run in the 64-bit environment.
 
 TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
-  ASSERT_DEATH({
-      SetUpInDeathAssert();
-      while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
-    }, kOomRegex);
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {
+    }
+  });
 }
 
 #endif  // !ARCH_CPU_64_BITS
@@ -559,8 +567,30 @@
 }
 #endif  // defined(ARCH_CPU_32_BITS) && (defined(OS_WIN) || defined(OS_LINUX))
 
-// TODO(b.kelemen): make UncheckedMalloc and UncheckedCalloc work
-// on Windows as well.
+// See the comment in |UncheckedMalloc()|, it behaves as malloc() in these
+// cases.
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) || defined(OS_ANDROID)
+
+TEST_F(OutOfMemoryDeathTest, UncheckedMallocDies) {
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    void* data;
+    bool ok = base::UncheckedMalloc(test_size_, &data);
+    EXPECT_TRUE(!data || ok);
+  });
+}
+
+TEST_F(OutOfMemoryDeathTest, UncheckedCallocDies) {
+  ASSERT_OOM_DEATH({
+    SetUpInDeathAssert();
+    void* data;
+    bool ok = base::UncheckedCalloc(1, test_size_, &data);
+    EXPECT_TRUE(!data || ok);
+  });
+}
+
+#else
+
 TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) {
   EXPECT_TRUE(base::UncheckedMalloc(kSafeMallocSize, &value_));
   EXPECT_TRUE(value_ != nullptr);
@@ -589,5 +619,8 @@
   EXPECT_FALSE(base::UncheckedCalloc(1, test_size_, &value_));
   EXPECT_TRUE(value_ == nullptr);
 }
-#endif  // !defined(OS_OPENBSD) && BUILDFLAG(ENABLE_WIN_ALLOCATOR_SHIM_TESTS) &&
+
+#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) || defined(OS_ANDROID)
+
+#endif  // !defined(OS_OPENBSD) && BUILDFLAG(USE_ALLOCATOR_SHIM) &&
         // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index dbcddb3..5a0984f 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -694,10 +694,16 @@
     ldflags += [ "-Wl,--no-rosegment" ]
   }
 
-  # Don't do call-graph-sorted binary layout on Android, as that increases the
-  # binary size due to more thunks for long jumps.
-  if (use_lld && is_android) {
-    ldflags += [ "-Wl,--no-call-graph-profile-sort" ]
+  # LLD does call-graph-sorted binary layout by default when profile data is
+  # present. On Android this increases binary size due to more thinks for long
+  # jumps. Turn it off by default and enable selectively for targets where it's
+  # beneficial.
+  if (use_lld) {
+    if (is_win) {
+      ldflags += [ "/call-graph-profile-sort:no" ]
+    } else {
+      ldflags += [ "-Wl,--no-call-graph-profile-sort" ]
+    }
   }
 
   # This flag enforces that member pointer base types are complete. It helps
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index e408268..a626d44a 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200803.0.1
+0.20200803.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 3d997cb..a626d44a 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200802.3.1
+0.20200803.1.1
diff --git a/buildtools/.gitignore b/buildtools/.gitignore
index 98d4676..163894f 100644
--- a/buildtools/.gitignore
+++ b/buildtools/.gitignore
@@ -1,16 +1,16 @@
 *.pyc
+android/doclava.tar.gz
+android/doclava/
 clang_format/script/
+linux64/.versions
+linux64/clang-format
+linux64/gn
+mac/.versions
+mac/clang-format
+mac/gn
 third_party/libc++/trunk
 third_party/libc++abi/trunk
 third_party/libunwind/trunk
-linux64/clang-format
-linux64/gn
-linux64/.versions
-mac/clang-format
-mac/gn
-mac/.versions
+win/.versions
 win/clang-format.exe
 win/gn.exe
-win/.versions
-android/doclava/
-android/doclava.tar.gz
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 4701a20..7d21e1e5 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -593,6 +593,7 @@
     "//services/viz/privileged/mojom",
     "//skia",
     "//testing/gtest",
+    "//ui/base:features",
     "//ui/gfx",
     "//ui/gfx:test_support",
     "//ui/gfx/geometry",
diff --git a/cc/test/DEPS b/cc/test/DEPS
index f04dd215..24c8b94 100644
--- a/cc/test/DEPS
+++ b/cc/test/DEPS
@@ -12,6 +12,7 @@
   "+gpu/ipc",
   "+services/viz/privileged/mojom/gl/gpu_host.mojom.h",
   "+services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h",
+  "+ui/base/ui_base_features.h",
 ]
 
 specific_include_rules = {
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index ea7eb06..1c469cb 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -50,6 +50,7 @@
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gl/gl_switches.h"
 
@@ -621,7 +622,8 @@
   // Tests should timeout quickly unless --cc-layer-tree-test-no-timeout was
   // specified (for running in a debugger).
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(switches::kCCLayerTreeTestNoTimeout))
+  if (!command_line->HasSwitch(switches::kCCLayerTreeTestNoTimeout)) {
+    timeout_seconds_ = 10;
 #if defined(THREAD_SANITIZER)
     // SwiftShader is a multi-threaded renderer and TSAN takes a lot longer to
     // run tests when using SwiftShader
@@ -639,13 +641,20 @@
     BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC) || BUILDFLAG(CFI_ENFORCEMENT_TRAP)
     // CFI is slow as well.
     timeout_seconds_ = 20;
-#elif defined(ADDRESS_SANITIZER) || defined(_DEBUG) || defined(USE_OZONE)
-    // ASAN and Debug builds are slower than release builds, as expected
-    // Ozone builds also go through a slower path than regular Linux builds
+#elif defined(ADDRESS_SANITIZER) || defined(_DEBUG)
+    // ASAN and Debug builds are slower than release builds, as expected.
     timeout_seconds_ = 30;
-#else
-    timeout_seconds_ = 10;
+#elif defined(USE_OZONE)
+    // Ozone builds go through a slower path than regular Linux builds.
+    // TODO(https://crbug.com/1096425): This special case of having both Ozone
+    // and X11 enabled that will be removed when Ozone is the default. Until
+    // then, we only need to use the slower Ozone timeout when the Ozone
+    // platform is being used. Remove this condition once it is not needed.
+    if (features::IsUsingOzonePlatform())
+      timeout_seconds_ = 30;
 #endif
+  }
+
   if (command_line->HasSwitch(switches::kCCLayerTreeTestLongTimeout))
     timeout_seconds_ = 5 * 60;
 
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
index e0c0c7d..b246ed73 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -92,6 +92,9 @@
     /** A token held while the assistant is obscuring all tabs. */
     private int mObscuringToken;
 
+    /** Height of the sheet's shadow used to compute the resize offset. */
+    private int mShadowHeight;
+
     AssistantBottomBarCoordinator(Activity activity, AssistantModel model,
             BottomSheetController controller,
             ApplicationViewportInsetSupplier applicationViewportInsetSupplier,
@@ -101,6 +104,9 @@
         mBottomSheetController = controller;
         mTabObscuringHandler = tabObscuringHandler;
 
+        mShadowHeight = activity.getResources().getDimensionPixelSize(
+                R.dimen.bottom_sheet_toolbar_shadow_height);
+
         mWindowApplicationInsetSupplier = applicationViewportInsetSupplier;
         mWindowApplicationInsetSupplier.addSupplier(mInsetSupplier);
 
@@ -410,8 +416,11 @@
             return;
         }
 
-        setVisualViewportResizing((int) Math.floor(mBottomSheetController.getCurrentOffset()
-                - mBottomSheetController.getTopShadowHeight()));
+        // In order to align the bottom of a website with the top of the bottom sheet, we need to
+        // remove the shadow height from the sheet's current offset. Note that mShadowHeight is
+        // different from the sheet controller's getTopShadowHeight().
+        int offset = mBottomSheetController.getCurrentOffset() - mShadowHeight;
+        setVisualViewportResizing(offset);
     }
 
     private void resetVisualViewportHeight() {
diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
index cdb692da0..e1a4f38f 100644
--- a/chrome/android/java/res/xml/main_preferences.xml
+++ b/chrome/android/java/res/xml/main_preferences.xml
@@ -7,22 +7,25 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:orderingFromXml="false">
 
+    <org.chromium.chrome.browser.sync.settings.SyncPromoPreference
+        android:key="sync_promo"
+        android:order="0"/>
     <PreferenceCategory
         android:key="account_section"
-        android:order="0"
+        android:order="1"
         android:title="@string/prefs_section_account"/>
     <PreferenceCategory
         android:key="account_and_google_services_section"
-        android:order="1"
+        android:order="2"
         android:title="@string/prefs_section_account_and_google_services"
         app:isPreferenceVisible="false"/>
     <org.chromium.chrome.browser.sync.settings.SignInPreference
         android:key="sign_in"
-        android:order="2"
+        android:order="3"
         android:title="@string/sign_in_to_chrome"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:key="sync_and_services"
-        android:order="3"
+        android:order="4"
         android:layout="@layout/account_management_account_row"
         android:title="@string/prefs_sync_and_services"
         android:fragment="org.chromium.chrome.browser.sync.settings.SyncAndServicesSettings"/>
@@ -30,13 +33,13 @@
          is enabled. -->
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:key="manage_sync"
-        android:order="4"
+        android:order="5"
         android:title="@string/sync_category_title"
         android:fragment="org.chromium.chrome.browser.sync.settings.ManageSyncSettings"
         app:isPreferenceVisible="false"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:key="google_services"
-        android:order="5"
+        android:order="6"
         android:title="@string/services_category_title"
         android:icon="@drawable/ic_google_services_48dp"
         android:fragment="org.chromium.chrome.browser.sync.settings.GoogleServicesSettings"
@@ -44,93 +47,93 @@
 
     <PreferenceCategory
         android:key="basics_section"
-        android:order="6"
+        android:order="7"
         android:title="@string/prefs_section_basics"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.search_engines.settings.SearchEngineSettings"
         android:key="search_engine"
-        android:order="7"
+        android:order="8"
         android:title="@string/search_engine_settings"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.password_manager.settings.PasswordSettings"
         android:key="passwords"
-        android:order="8"
+        android:order="9"
         android:title="@string/password_settings_title"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.autofill.settings.AutofillPaymentMethodsFragment"
         android:key="autofill_payment_methods"
-        android:order="9"
+        android:order="10"
         android:title="@string/autofill_payment_methods"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.autofill.settings.AutofillProfilesFragment"
         android:key="autofill_addresses"
-        android:order="10"
+        android:order="11"
         android:title="@string/autofill_addresses_settings_title"/>
-    <!-- android:order="11" is reserved for "Privacy" behind the privacy-elevated-android flag. -->
+    <!-- android:order="12" is reserved for "Privacy" behind the privacy-elevated-android flag. -->
     <Preference
         android:fragment="org.chromium.chrome.browser.safety_check.SafetyCheckSettingsFragment"
         android:key="safety_check"
-        android:order="12"
+        android:order="13"
         android:title="@string/prefs_safety_check"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.notifications.settings.NotificationSettings"
         android:key="notifications"
-        android:order="13"
+        android:order="14"
         android:title="@string/prefs_notifications"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.homepage.settings.HomepageSettings"
         android:key="homepage"
-        android:order="14"
+        android:order="15"
         android:title="@string/options_homepage_title"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.night_mode.settings.ThemeSettingsFragment"
         android:key="ui_theme"
-        android:order="15"
+        android:order="16"
         android:title="@string/theme_settings" />
 
     <PreferenceCategory
         android:key="advanced_section"
-        android:order="16"
+        android:order="17"
         android:title="@string/prefs_section_advanced"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.privacy.settings.PrivacySettings"
         android:key="privacy"
-        android:order="17"
+        android:order="18"
         android:title="@string/prefs_privacy"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.accessibility.settings.AccessibilitySettings"
         android:key="accessibility"
-        android:order="18"
+        android:order="19"
         android:title="@string/prefs_accessibility"/>
     <Preference
         android:fragment="org.chromium.components.browser_ui.site_settings.SiteSettings"
         android:key="content_settings"
-        android:order="19"
+        android:order="20"
         android:title="@string/prefs_site_settings"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.language.settings.LanguageSettings"
         android:key="languages"
-        android:order="20"
+        android:order="21"
         android:title="@string/language_settings"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.datareduction.settings.DataReductionPreferenceFragment"
         android:key="data_reduction"
-        android:order="21"
+        android:order="22"
         android:title="@string/data_reduction_title_lite_mode"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.download.settings.DownloadSettings"
         android:key="downloads"
-        android:order="22"
+        android:order="23"
         android:title="@string/menu_downloads"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.tracing.settings.DeveloperSettings"
         android:key="developer"
-        android:order="23"
+        android:order="24"
         android:title="Developer options"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.about_settings.AboutChromeSettings"
         android:key="about_chrome"
-        android:order="24"
+        android:order="25"
         android:title="@string/prefs_about_chrome"/>
 
 </PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
index 675f89b..83b6c27 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -35,6 +35,7 @@
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.settings.SignInPreference;
+import org.chromium.chrome.browser.sync.settings.SyncPromoPreference;
 import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils;
 import org.chromium.chrome.browser.tracing.settings.DeveloperSettings;
 import org.chromium.components.browser_ui.settings.ChromeBasePreference;
@@ -52,6 +53,7 @@
 public class MainSettings extends PreferenceFragmentCompat
         implements TemplateUrlService.LoadListener, ProfileSyncService.SyncStateChangedListener,
                    SigninManager.SignInStateObserver {
+    public static final String PREF_SYNC_PROMO = "sync_promo";
     public static final String PREF_ACCOUNT_SECTION = "account_section";
     public static final String PREF_ACCOUNT_AND_GOOGLE_SERVICES_SECTION =
             "account_and_google_services_section";
@@ -71,11 +73,12 @@
     public static final String PREF_DEVELOPER = "developer";
 
     // Used for elevating the privacy section behind the flag (see crbug.com/1099233).
-    public static final int PRIVACY_ORDER_DEFAULT = 17;
-    public static final int PRIVACY_ORDER_ELEVATED = 11;
+    public static final int PRIVACY_ORDER_DEFAULT = 18;
+    public static final int PRIVACY_ORDER_ELEVATED = 12;
 
     private final ManagedPreferenceDelegate mManagedPreferenceDelegate;
     private final Map<String, Preference> mAllPreferences = new HashMap<>();
+    private SyncPromoPreference mSyncPromoPreference;
     private SignInPreference mSignInPreference;
     private ChromeBasePreference mManageSync;
     private @Nullable PasswordCheck mPasswordCheck;
@@ -107,6 +110,7 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        mSyncPromoPreference.onPreferenceFragmentDestroyed();
         mSignInPreference.onPreferenceFragmentDestroyed();
         // The component should only be destroyed when the activity has been closed by the user
         // (e.g. by pressing on the back button) and not when the activity is temporarily destroyed
@@ -121,6 +125,7 @@
                 Profile.getLastUsedRegularProfile());
         if (signinManager.isSigninSupported()) {
             signinManager.addSignInStateObserver(this);
+            mSyncPromoPreference.registerForUpdates();
             mSignInPreference.registerForUpdates();
         }
         ProfileSyncService syncService = ProfileSyncService.get();
@@ -136,6 +141,7 @@
                 Profile.getLastUsedRegularProfile());
         if (signinManager.isSigninSupported()) {
             signinManager.removeSignInStateObserver(this);
+            mSyncPromoPreference.unregisterForUpdates();
             mSignInPreference.unregisterForUpdates();
         }
         ProfileSyncService syncService = ProfileSyncService.get();
@@ -247,6 +253,7 @@
             Preference preference = getPreferenceScreen().getPreference(index);
             mAllPreferences.put(preference.getKey(), preference);
         }
+        mSyncPromoPreference = (SyncPromoPreference) mAllPreferences.get(PREF_SYNC_PROMO);
         mSignInPreference = (SignInPreference) mAllPreferences.get(PREF_SIGN_IN);
         mManageSync = (ChromeBasePreference) findPreference(PREF_MANAGE_SYNC);
     }
@@ -268,9 +275,11 @@
         boolean hasPrimaryAccount = IdentityServicesProvider.get()
                                             .getIdentityManager(Profile.getLastUsedRegularProfile())
                                             .hasPrimaryAccount();
+        boolean isSyncPromoHidden =
+                mSyncPromoPreference.getState() == SyncPromoPreference.State.PROMO_HIDDEN;
         mManageSync.setVisible(
                 ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
-                && hasPrimaryAccount);
+                && hasPrimaryAccount && isSyncPromoHidden);
 
         updateSyncAndServicesPreference();
         updateSearchEnginePreference();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
index e9e0bc1d..29e0ef31 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
@@ -83,7 +83,7 @@
             AccountPickerBottomSheetCoordinator coordinator =
                     new AccountPickerBottomSheetCoordinator(activity,
                             BottomSheetControllerProvider.from(activity.getWindowAndroid()),
-                            new AccountPickerDelegate(activity, continueUrl));
+                            new AccountPickerDelegate(windowAndroid, continueUrl));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
index a8e206b..b136133 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
@@ -68,7 +68,7 @@
      */
     @Override
     public void addAccount() {
-        mAccountPickerDelegate.addAccount();
+        mAccountPickerDelegate.addAccount(accountName -> onAccountSelected(accountName, false));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerDelegate.java
index 1a7a699..810d5132 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerDelegate.java
@@ -5,10 +5,13 @@
 package org.chromium.chrome.browser.signin.account_picker;
 
 import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Activity;
 import android.content.Intent;
 
 import androidx.annotation.Nullable;
 
+import org.chromium.base.Callback;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -21,6 +24,7 @@
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
+import org.chromium.ui.base.WindowAndroid;
 
 /**
  * This class is used in web sign-in flow for the account picker bottom sheet.
@@ -29,14 +33,15 @@
  * web sign-in flow.
  */
 public class AccountPickerDelegate {
+    private final WindowAndroid mWindowAndroid;
     private final ChromeActivity mChromeActivity;
     private final Tab mTab;
     private final String mContinueUrl;
     private final SigninManager mSigninManager;
 
-    public AccountPickerDelegate(ChromeActivity chromeActivity, String continueUrl) {
-        mChromeActivity = chromeActivity;
-        // TODO(https://crbug.com/1095554): Check if website redirects after sign-in
+    public AccountPickerDelegate(WindowAndroid windowAndroid, String continueUrl) {
+        mWindowAndroid = windowAndroid;
+        mChromeActivity = (ChromeActivity) mWindowAndroid.getActivity().get();
         mTab = mChromeActivity.getActivityTab();
         mContinueUrl = continueUrl;
         mSigninManager = IdentityServicesProvider.get().getSigninManager(
@@ -70,13 +75,22 @@
     /**
      * Notifies when the user clicked the "add account" button.
      */
-    public void addAccount() {
-        // TODO(https//crbug.com/1097031): We should select the added account
-        // and collapse the account chooser after the account is actually added.
+    public void addAccount(Callback<String> callback) {
         AccountManagerFacadeProvider.getInstance().createAddAccountIntent(
                 (@Nullable Intent intent) -> {
                     if (intent != null) {
-                        mChromeActivity.startActivity(intent);
+                        WindowAndroid.IntentCallback intentCallback =
+                                new WindowAndroid.IntentCallback() {
+                                    @Override
+                                    public void onIntentCompleted(
+                                            WindowAndroid window, int resultCode, Intent data) {
+                                        if (resultCode == Activity.RESULT_OK) {
+                                            callback.onResult(data.getStringExtra(
+                                                    AccountManager.KEY_ACCOUNT_NAME));
+                                        }
+                                    }
+                                };
+                        mWindowAndroid.showIntent(intent, intentCallback, null);
                     } else {
                         // AccountManagerFacade couldn't create intent, use SigninUtils to open
                         // settings instead.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
index 484f962..ef4ed884 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
@@ -13,7 +13,6 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.permissions.PermissionTestRule.PermissionUpdateWaiter;
 import org.chromium.chrome.browser.tab.Tab;
@@ -58,7 +57,6 @@
     @MediumTest
     @Feature({"MediaPermissions", "Main"})
     @CommandLineFlags.Add({FAKE_DEVICE})
-    @FlakyTest
     public void testMicrophoneMediaPermissionsPlumbingDialog() throws Exception {
         testMediaPermissionsPlumbing("Mic count:", "initiate_getMicrophone()", 1, true, true);
     }
@@ -72,7 +70,6 @@
     @MediumTest
     @Feature({"MediaPermissions", "Main"})
     @CommandLineFlags.Add({FAKE_DEVICE})
-    @FlakyTest
     public void testCameraPermissionsPlumbingDialog() throws Exception {
         testMediaPermissionsPlumbing("Camera count:", "initiate_getCamera()", 1, false, true);
     }
@@ -86,7 +83,6 @@
     @MediumTest
     @Feature({"MediaPermissions", "Main"})
     @CommandLineFlags.Add({FAKE_DEVICE})
-    @FlakyTest
     public void testCombinedPermissionsPlumbingDialog() throws Exception {
         testMediaPermissionsPlumbing("Combined count:", "initiate_getCombined()", 1, true, true);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
index 654e00e..1fe4a78 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
@@ -294,6 +294,13 @@
      * Utility functions to support permissions testing in other contexts.
      */
     public static void replyToDialog(boolean allow, ChromeActivity activity) {
+        // Wait a tiny bit before clicking the dialog. Sometimes the click happens too quick and the
+        // dialog is not ready. See crbug.com/1098806 for example flaky tests.
+        try {
+            Thread.sleep(300);
+        } catch (Exception ex) {
+        }
+
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             TabModalPresenter presenter = (TabModalPresenter) activity.getModalDialogManager()
                                                   .getCurrentPresenterForTest();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
index 3d13fe1..8a6ac8d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -18,6 +18,7 @@
 
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.core.AllOf.allOf;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.verify;
 import static org.mockito.MockitoAnnotations.initMocks;
 
@@ -31,8 +32,11 @@
 import org.junit.Test;
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 
+import org.chromium.base.Callback;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
@@ -51,6 +55,7 @@
 import org.chromium.components.signin.ProfileDataSource;
 import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
 import org.chromium.components.signin.test.util.FakeProfileDataSource;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.io.IOException;
@@ -85,6 +90,9 @@
     public final ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus().setRevision(0).build();
 
+    @Captor
+    public ArgumentCaptor<Callback<String>> callbackArgumentCaptor;
+
     private final ChromeTabbedActivityTestRule mActivityTestRule =
             new ChromeTabbedActivityTestRule();
 
@@ -299,7 +307,16 @@
     public void testAddAccountOnExpandedSheet() {
         buildAndShowExpandedBottomSheet();
         onView(withText(R.string.signin_add_account_to_device)).perform(click());
-        verify(mAccountPickerDelegateMock).addAccount();
+        verify(mAccountPickerDelegateMock).addAccount(callbackArgumentCaptor.capture());
+        ProfileDataSource.ProfileData profileDataAdded = new ProfileDataSource.ProfileData(
+                /* accountName= */ "test.account3@gmail.com", /* avatar= */ null,
+                /* fullName= */ null, /* givenName= */ null);
+        Callback<String> callback = callbackArgumentCaptor.getValue();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> callback.onResult(profileDataAdded.getAccountName()));
+        CriteriaHelper.pollUiThread(mCoordinator.getBottomSheetViewForTesting().findViewById(
+                R.id.account_picker_selected_account)::isShown);
+        checkCollapsedAccountList(profileDataAdded);
     }
 
     @Test
@@ -338,7 +355,7 @@
         onView(allOf(withText(R.string.signin_add_account_to_device),
                        withEffectiveVisibility(VISIBLE)))
                 .perform(click());
-        verify(mAccountPickerDelegateMock).addAccount();
+        verify(mAccountPickerDelegateMock).addAccount(notNull());
     }
 
     private void checkCollapsedAccountList(ProfileDataSource.ProfileData profileData) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tracing/settings/TracingSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tracing/settings/TracingSettingsTest.java
index 61fe976c..adb53bd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tracing/settings/TracingSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tracing/settings/TracingSettingsTest.java
@@ -10,7 +10,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build.VERSION_CODES;
 import android.support.test.InstrumentationRegistry;
 import android.util.Pair;
 
@@ -147,8 +146,7 @@
     @MediumTest
     @Feature({"Preferences"})
     @DisabledTest
-    @DisableIf.Build(sdk_is_less_than = VERSION_CODES.M,
-            message = "crbug.com/899894 (for <L), crbug.com/1111816 (for L)")
+    @DisableIf.Build(sdk_is_less_than = 21, message = "crbug.com/899894")
     public void testRecordTrace() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
         mSettingsActivityTestRule.startSettingsActivity();
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 07db57e3..efbd567b 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4567,7 +4567,7 @@
     Upgrade Linux (Beta)
   </message>
   <message name="IDS_CROSTINI_UPGRADER_BODY" desc="Description for the Crostini upgrader, a dialog for upgrading Linux.">
-    Backing up files is recommended as part of this upgrade to prevent data loss in case the upgrade cannot be completed. Starting the upgrade will cause Linux (Beta) to shut down. Please save open files before proceeding.
+    Backing up files is recommended in case the upgrade cannot be completed. Starting the upgrade will cause Linux (Beta) to shut down. Please save open files before proceeding.
   </message>
   <message name="IDS_CROSTINI_UPGRADER_UPGRADE_BUTTON" desc="Label for the button in the Crostini upgrader dialog to begin upgrading Linux.">
     Upgrade
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1
index ab2fd6c..19369ca 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1
@@ -1 +1 @@
-b64d3b1e7d85a297e917069c7213221e208b23cf
\ No newline at end of file
+9a74cf08f0b34eaaf6a4fe8155985b88410039ec
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index c156f42..86a5f92 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -391,9 +391,6 @@
   <message name="IDS_SETTINGS_COMPROMISED_PASSWORD_HIDE" desc="Action menu item for a row which displays a compromised password. The password value, which is shown in plain text, will be hidden again.">
     Hide password
   </message>
-  <message name="IDS_SETTINGS_COMPROMISED_PASSWORD_EDIT" desc="Action menu item for a row which displays a compromised password. It will open a modal dialog which will allow the user to edit the password and other metadata (username, website).">
-    Edit password
-  </message>
   <message name="IDS_SETTINGS_COMPROMISED_PASSWORD_REMOVE" desc="Action menu item for a row which displays a compromised password. It will open a confirmation dialog for deleting the password.">
     Remove password
   </message>
@@ -403,12 +400,6 @@
   <message name="IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_DESCRIPTION" desc="Compromised password remove dialog conformation description">
     Removing this password will not delete your account on <ph name="DOMAIN">$1<ex>airbnb.com</ex></ph>. Change your password or delete your account on <ph name="DOMAIN_LINK">$2<ex>&lt;a href="https://airbnb.com" target="_blank"&gt;airbnb.com&lt;/a&gt;</ex></ph> to keep it safe from others.
   </message>
-  <message name="IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_TITLE" desc="The title for a dialog, which allows a user to edit a password, which have been found to be compromised. This dialog includes other details, such as username and website.">
-    Edit password
-  </message>
-  <message name="IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_FOOTNOTE" desc="A footnote for the dialog which allows the user to edit a password, which has been found to have been compromised.">
-    Make sure the password you are saving matches your password for <ph name="WEBSITE">$1<ex>airbnb.com</ex></ph>
-  </message>
   <message name="IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_SITE" desc="A label for the field, which displays the site for which the password was saved. The field is part of a dialog, which allows the user to edit the password.">
     Site
   </message>
@@ -466,6 +457,15 @@
   <message name="IDS_SETTINGS_PASSWORD_DETAILS" desc="Label for a context menu item that shows a dialog with details for the selected password.">
     Details
   </message>
+  <message name="IDS_SETTINGS_PASSWORD_EDIT_TITLE" desc="The title for a dialog, which allows a user to edit a saved password. This dialog includes other details, such as username and website.">
+    Edit password
+  </message>
+  <message name="IDS_SETTINGS_PASSWORD_EDIT" desc="Action menu item for a row which displays a saved password. It will open a modal dialog which will allow the user to edit the password and other metadata (username, website).">
+    Edit password
+  </message>
+  <message name="IDS_SETTINGS_PASSWORD_EDIT_FOOTNOTE" desc="A footnote for the dialog which allows the user to edit a saved password.">
+    Make sure the password you are saving matches your password for <ph name="WEBSITE">$1<ex>airbnb.com</ex></ph>
+  </message>
   <message name="IDS_SETTINGS_PASSWORD_COPY" desc="Label for a context menu item that allows to copy the selected password into clipboard.">
     Copy password
   </message>
@@ -1265,7 +1265,7 @@
   <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_MORE_BUTTON_ARIA_LABEL" desc="Accessiblity text for the button that leads users to the Chrome cleaner page, which explains details about the device softrware check.">
     Show details of the device software check
   </message>
-  
+
   <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_LABEL" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include browser-initiated DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
     Preload pages for faster browsing and searching
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_COMPROMISED_PASSWORD_EDIT.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_EDIT.png.sha1
similarity index 100%
rename from chrome/app/settings_strings_grdp/IDS_SETTINGS_COMPROMISED_PASSWORD_EDIT.png.sha1
rename to chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_EDIT.png.sha1
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_FOOTNOTE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_EDIT_FOOTNOTE.png.sha1
similarity index 100%
rename from chrome/app/settings_strings_grdp/IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_FOOTNOTE.png.sha1
rename to chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_EDIT_FOOTNOTE.png.sha1
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_EDIT_TITLE.png.sha1
similarity index 100%
rename from chrome/app/settings_strings_grdp/IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_TITLE.png.sha1
rename to chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_EDIT_TITLE.png.sha1
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 19f1c708..739fdd9 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3313,6 +3313,8 @@
       "metrics/tab_stats_tracker.cc",
       "metrics/tab_stats_tracker.h",
       "metrics/tab_stats_tracker_delegate.h",
+      "nearby_sharing/attachment_info.cc",
+      "nearby_sharing/attachment_info.h",
       "nearby_sharing/fast_initiation_manager.cc",
       "nearby_sharing/fast_initiation_manager.h",
       "nearby_sharing/incoming_frames_reader.cc",
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 7f7ffcd..a01ed3e 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -817,8 +817,7 @@
 
   // For BROWSE state the back button should react in its default way.
   if (ui_delegate_ != nullptr &&
-      (ui_delegate_->GetState() == AutofillAssistantState::BROWSE ||
-       !ui_delegate_->ShouldShowOverlay())) {
+      ui_delegate_->GetState() == AutofillAssistantState::BROWSE) {
     return false;
   }
 
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
index fc75558..16bc46f 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/favicon/core/large_icon_service_impl.h"
-#include "components/favicon_base/favicon_types.h"
 #include "components/image_fetcher/core/image_fetcher.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.h b/chrome/browser/android/bookmarks/partner_bookmarks_reader.h
index f0aa732..a1f00d62 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_reader.h
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.h
@@ -12,6 +12,7 @@
 #include "base/android/jni_weak_ref.h"
 #include "base/macros.h"
 #include "components/bookmarks/browser/bookmark_node.h"
+#include "components/favicon_base/favicon_types.h"
 
 namespace favicon {
 class LargeIconService;
diff --git a/chrome/browser/bookmarks/chrome_bookmark_client.cc b/chrome/browser/bookmarks/chrome_bookmark_client.cc
index cbc59aa..b3fe47b 100644
--- a/chrome/browser/bookmarks/chrome_bookmark_client.cc
+++ b/chrome/browser/bookmarks/chrome_bookmark_client.cc
@@ -15,6 +15,7 @@
 #include "components/bookmarks/managed/managed_bookmark_service.h"
 #include "components/bookmarks/managed/managed_bookmark_util.h"
 #include "components/favicon/core/favicon_util.h"
+#include "components/favicon_base/favicon_types.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/url_database.h"
 #include "components/offline_pages/buildflags/buildflags.h"
@@ -47,20 +48,15 @@
 #endif
 }
 
-bool ChromeBookmarkClient::PreferTouchIcon() {
-  return false;
-}
-
 base::CancelableTaskTracker::TaskId
 ChromeBookmarkClient::GetFaviconImageForPageURL(
     const GURL& page_url,
-    favicon_base::IconType type,
     favicon_base::FaviconImageCallback callback,
     base::CancelableTaskTracker* tracker) {
   return favicon::GetFaviconImageForPageURL(
       FaviconServiceFactory::GetForProfile(profile_,
                                            ServiceAccessType::EXPLICIT_ACCESS),
-      page_url, type, std::move(callback), tracker);
+      page_url, favicon_base::IconType::kFavicon, std::move(callback), tracker);
 }
 
 bool ChromeBookmarkClient::SupportsTypedCountForUrls() {
diff --git a/chrome/browser/bookmarks/chrome_bookmark_client.h b/chrome/browser/bookmarks/chrome_bookmark_client.h
index 22d20219..36b2d2f2 100644
--- a/chrome/browser/bookmarks/chrome_bookmark_client.h
+++ b/chrome/browser/bookmarks/chrome_bookmark_client.h
@@ -5,7 +5,10 @@
 #ifndef CHROME_BROWSER_BOOKMARKS_CHROME_BOOKMARK_CLIENT_H_
 #define CHROME_BROWSER_BOOKMARKS_CHROME_BOOKMARK_CLIENT_H_
 
+#include <memory>
 #include <set>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "base/deferred_sequenced_task_runner.h"
@@ -42,10 +45,8 @@
 
   // bookmarks::BookmarkClient:
   void Init(bookmarks::BookmarkModel* model) override;
-  bool PreferTouchIcon() override;
   base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
       const GURL& page_url,
-      favicon_base::IconType type,
       favicon_base::FaviconImageCallback callback,
       base::CancelableTaskTracker* tracker) override;
   bool SupportsTypedCountForUrls() override;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index a7d40e3..3b58ff4 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -710,6 +710,8 @@
     "arc/screen_capture/arc_screen_capture_bridge.h",
     "arc/screen_capture/arc_screen_capture_session.cc",
     "arc/screen_capture/arc_screen_capture_session.h",
+    "arc/session/adb_sideloading_availability_delegate_impl.cc",
+    "arc/session/adb_sideloading_availability_delegate_impl.h",
     "arc/session/arc_play_store_enabled_preference_handler.cc",
     "arc/session/arc_play_store_enabled_preference_handler.h",
     "arc/session/arc_service_launcher.cc",
@@ -1992,6 +1994,8 @@
     "policy/display_settings_handler.h",
     "policy/dlp/dlp_content_manager.cc",
     "policy/dlp/dlp_content_manager.h",
+    "policy/dlp/dlp_content_restriction_set.cc",
+    "policy/dlp/dlp_content_restriction_set.h",
     "policy/dlp/dlp_content_tab_helper.cc",
     "policy/dlp/dlp_content_tab_helper.h",
     "policy/dlp/enterprise_clipboard_dlp_controller.cc",
diff --git a/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc b/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
index b2afccbb..bb9d31e1 100644
--- a/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
+++ b/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
@@ -28,8 +28,10 @@
   ArcBootPhaseThrottleObserverTest()
       : scoped_user_manager_(
             std::make_unique<chromeos::FakeChromeUserManager>()),
-        arc_session_manager_(std::make_unique<ArcSessionRunner>(
-            base::Bind(FakeArcSession::Create))) {
+        arc_session_manager_(
+            std::make_unique<ArcSessionRunner>(
+                base::Bind(FakeArcSession::Create)),
+            std::make_unique<AdbSideloadingAvailabilityDelegateImpl>()) {
     // Setup and login profile
     SetArcAvailableCommandLineForTesting(
         base::CommandLine::ForCurrentProcess());
diff --git a/chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.cc b/chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.cc
new file mode 100644
index 0000000..66dbc6b
--- /dev/null
+++ b/chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.cc
@@ -0,0 +1,34 @@
+// 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 "chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.h"
+
+#include "chrome/browser/chromeos/crostini/crostini_features.h"
+
+namespace arc {
+
+AdbSideloadingAvailabilityDelegateImpl::
+    AdbSideloadingAvailabilityDelegateImpl() = default;
+
+AdbSideloadingAvailabilityDelegateImpl::
+    ~AdbSideloadingAvailabilityDelegateImpl() = default;
+
+void AdbSideloadingAvailabilityDelegateImpl::SetProfile(Profile* profile) {
+  profile_ = profile;
+}
+
+void AdbSideloadingAvailabilityDelegateImpl::CanChangeAdbSideloading(
+    base::OnceCallback<void(bool can_change_adb_sideloading)> callback) {
+  if (!profile_) {
+    // If |profile_| is not set, return immediately and mark adb sideloading as
+    // not allowed
+    std::move(callback).Run(false);
+    return;
+  }
+
+  crostini::CrostiniFeatures::Get()->CanChangeAdbSideloading(
+      profile_, std::move(callback));
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.h b/chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.h
new file mode 100644
index 0000000..612735a
--- /dev/null
+++ b/chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.h
@@ -0,0 +1,40 @@
+// 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 CHROME_BROWSER_CHROMEOS_ARC_SESSION_ADB_SIDELOADING_AVAILABILITY_DELEGATE_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_SESSION_ADB_SIDELOADING_AVAILABILITY_DELEGATE_IMPL_H_
+
+#include "components/arc/session/adb_sideloading_availability_delegate.h"
+
+#include "chrome/browser/profiles/profile.h"
+
+namespace arc {
+
+class AdbSideloadingAvailabilityDelegateImpl
+    : public AdbSideloadingAvailabilityDelegate {
+ public:
+  AdbSideloadingAvailabilityDelegateImpl();
+
+  // Not copyable or movable
+  AdbSideloadingAvailabilityDelegateImpl(
+      const AdbSideloadingAvailabilityDelegateImpl&) = delete;
+  AdbSideloadingAvailabilityDelegateImpl& operator=(
+      const AdbSideloadingAvailabilityDelegateImpl&) = delete;
+
+  ~AdbSideloadingAvailabilityDelegateImpl() override;
+
+  void SetProfile(Profile* profile);
+
+  void CanChangeAdbSideloading(
+      base::OnceCallback<void(bool can_change_adb_sideloading)> callback)
+      override;
+
+ private:
+  // Unowned pointer. Keeps current profile.
+  Profile* profile_ = nullptr;
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_SESSION_ADB_SIDELOADING_AVAILABILITY_DELEGATE_IMPL_H_
diff --git a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
index 99b79e8..29febf0 100644
--- a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
@@ -91,19 +91,31 @@
 // ChromeBrowserMainPartsChromeos owns.
 ArcServiceLauncher* g_arc_service_launcher = nullptr;
 
+std::unique_ptr<ArcSessionManager> CreateArcSessionManager(
+    ArcBridgeService* arc_bridge_service,
+    ash::DefaultScaleFactorRetriever* retriever,
+    version_info::Channel channel,
+    chromeos::SchedulerConfigurationManagerBase*
+        scheduler_configuration_manager) {
+  auto delegate = std::make_unique<AdbSideloadingAvailabilityDelegateImpl>();
+  auto runner = std::make_unique<ArcSessionRunner>(base::BindRepeating(
+      ArcSession::Create, arc_bridge_service, retriever, channel,
+      scheduler_configuration_manager, delegate.get()));
+  return std::make_unique<ArcSessionManager>(std::move(runner),
+                                             std::move(delegate));
+}
+
 }  // namespace
 
 ArcServiceLauncher::ArcServiceLauncher(
     chromeos::SchedulerConfigurationManagerBase*
         scheduler_configuration_manager)
     : arc_service_manager_(std::make_unique<ArcServiceManager>()),
-      arc_session_manager_(std::make_unique<ArcSessionManager>(
-          std::make_unique<ArcSessionRunner>(
-              base::BindRepeating(ArcSession::Create,
-                                  arc_service_manager_->arc_bridge_service(),
+      arc_session_manager_(
+          CreateArcSessionManager(arc_service_manager_->arc_bridge_service(),
                                   &default_scale_factor_retriever_,
                                   chrome::GetChannel(),
-                                  scheduler_configuration_manager)))),
+                                  scheduler_configuration_manager)),
       scheduler_configuration_manager_(scheduler_configuration_manager) {
   DCHECK(g_arc_service_launcher == nullptr);
   g_arc_service_launcher = this;
@@ -252,11 +264,10 @@
   // No recreation of arc_service_manager. Pointers to its ArcBridgeService
   // may be referred from existing KeyedService, so destoying it would cause
   // unexpected behavior, specifically on test teardown.
-  arc_session_manager_ = std::make_unique<ArcSessionManager>(
-      std::make_unique<ArcSessionRunner>(base::BindRepeating(
-          ArcSession::Create, arc_service_manager_->arc_bridge_service(),
-          &default_scale_factor_retriever_, chrome::GetChannel(),
-          scheduler_configuration_manager_)));
+  arc_session_manager_ = CreateArcSessionManager(
+      arc_service_manager_->arc_bridge_service(),
+      &default_scale_factor_retriever_, chrome::GetChannel(),
+      scheduler_configuration_manager_);
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.cc b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
index ba11df29..53bb6ca 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
@@ -443,8 +443,12 @@
 };
 
 ArcSessionManager::ArcSessionManager(
-    std::unique_ptr<ArcSessionRunner> arc_session_runner)
+    std::unique_ptr<ArcSessionRunner> arc_session_runner,
+    std::unique_ptr<AdbSideloadingAvailabilityDelegateImpl>
+        adb_sideloading_availability_delegate)
     : arc_session_runner_(std::move(arc_session_runner)),
+      adb_sideloading_availability_delegate_(
+          std::move(adb_sideloading_availability_delegate)),
       attempt_user_exit_callback_(base::Bind(chrome::AttemptUserExit)),
       property_files_source_dir_(base::FilePath(
           IsArcVmEnabled() ? kPropertyFilesPathVm : kPropertyFilesPath)),
@@ -739,6 +743,7 @@
   DCHECK(!profile_);
   DCHECK(IsArcAllowedForProfile(profile));
   profile_ = profile;
+  adb_sideloading_availability_delegate_->SetProfile(profile);
   // RequestEnable() requires |profile_| set, therefore shouldn't have been
   // called at this point.
   SetArcEnabledStateMetric(false);
@@ -756,10 +761,10 @@
   std::string serialno;
   // ARC container doesn't need the serial number.
   if (arc::IsArcVmEnabled()) {
-    const std::string chormeos_user =
+    const std::string chromeos_user =
         cryptohome::CreateAccountIdentifierFromAccountId(account).account_id();
     serialno = GetOrCreateSerialNumber(g_browser_process->local_state(),
-                                       chormeos_user, *arc_salt_on_disk_);
+                                       chromeos_user, *arc_salt_on_disk_);
   }
 
   arc_session_runner_->SetUserInfo(cryptohome_id, user_id_hash, serialno);
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.h b/chrome/browser/chromeos/arc/session/arc_session_manager.h
index 2067e44..1e3afe52 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.h
@@ -17,6 +17,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/arc/arc_app_id_provider_impl.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
+#include "chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager_observer.h"
 #include "chrome/browser/chromeos/policy/android_management_client.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
@@ -112,9 +113,9 @@
   using ExpansionResult = std::pair<std::string /* salt on disk */,
                                     bool /* expansion successful */>;
 
-
-  explicit ArcSessionManager(
-      std::unique_ptr<ArcSessionRunner> arc_session_runner);
+  ArcSessionManager(std::unique_ptr<ArcSessionRunner> arc_session_runner,
+                    std::unique_ptr<AdbSideloadingAvailabilityDelegateImpl>
+                        adb_sideloading_availability_delegate);
   ~ArcSessionManager() override;
 
   static ArcSessionManager* Get();
@@ -369,6 +370,8 @@
   void OnExpandPropertyFilesAndReadSalt(ExpansionResult result);
 
   std::unique_ptr<ArcSessionRunner> arc_session_runner_;
+  std::unique_ptr<AdbSideloadingAvailabilityDelegateImpl>
+      adb_sideloading_availability_delegate_;
 
   // Unowned pointer. Keeps current profile.
   Profile* profile_ = nullptr;
diff --git a/chrome/browser/chromeos/arc/test/test_arc_session_manager.cc b/chrome/browser/chromeos/arc/test/test_arc_session_manager.cc
index 492b138..1eb6a00 100644
--- a/chrome/browser/chromeos/arc/test/test_arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/test/test_arc_session_manager.cc
@@ -34,8 +34,9 @@
 
 std::unique_ptr<ArcSessionManager> CreateTestArcSessionManager(
     std::unique_ptr<ArcSessionRunner> arc_session_runner) {
-  auto manager =
-      std::make_unique<ArcSessionManager>(std::move(arc_session_runner));
+  auto manager = std::make_unique<ArcSessionManager>(
+      std::move(arc_session_runner),
+      std::make_unique<AdbSideloadingAvailabilityDelegateImpl>());
   // Our unit tests the ArcSessionManager::ExpandPropertyFiles() function won't
   // be automatically called. Because of that, we can call
   // OnExpandPropertyFilesForTesting() instead with |true| for easier unit
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
index 1844ddb..01c00840 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
@@ -20,13 +20,16 @@
   return g_dlp_content_manager;
 }
 
-bool DlpContentManager::IsWebContentsConfidential(
+DlpContentRestrictionSet DlpContentManager::GetConfidentialRestrictions(
     const content::WebContents* web_contents) const {
-  return base::Contains(confidential_web_contents_, web_contents);
+  if (!base::Contains(confidential_web_contents_, web_contents))
+    return DlpContentRestrictionSet();
+  return confidential_web_contents_.at(web_contents);
 }
 
-bool DlpContentManager::IsConfidentialDataPresentOnScreen() const {
-  return is_confidential_web_contents_visible_;
+DlpContentRestrictionSet DlpContentManager::GetOnScreenPresentRestrictions()
+    const {
+  return on_screen_restrictions_;
 }
 
 /* static */
@@ -48,11 +51,14 @@
 
 void DlpContentManager::OnConfidentialityChanged(
     content::WebContents* web_contents,
-    bool confidential) {
-  if (confidential) {
-    AddToConfidential(web_contents);
-  } else {
+    const DlpContentRestrictionSet& restriction_set) {
+  if (restriction_set.IsEmpty()) {
     RemoveFromConfidential(web_contents);
+  } else {
+    confidential_web_contents_[web_contents] = restriction_set;
+    if (web_contents->GetVisibility() == content::Visibility::VISIBLE) {
+      MaybeChangeOnScreenRestrictions();
+    }
   }
 }
 
@@ -61,46 +67,40 @@
   RemoveFromConfidential(web_contents);
 }
 
-bool DlpContentManager::IsURLConfidential(const GURL& url) const {
+DlpContentRestrictionSet DlpContentManager::GetRestrictionSetForURL(
+    const GURL& url) const {
+  DlpContentRestrictionSet set;
   // TODO(crbug/1109783): Implement based on the policy.
-  return false;
+  return set;
 }
 
-void DlpContentManager::OnVisibilityChanged(content::WebContents* web_contents,
-                                            bool visible) {
-  MaybeChangeVisibilityFlag();
-}
-
-void DlpContentManager::AddToConfidential(content::WebContents* web_contents) {
-  confidential_web_contents_.insert(web_contents);
-  if (web_contents->GetVisibility() == content::Visibility::VISIBLE) {
-    MaybeChangeVisibilityFlag();
-  }
+void DlpContentManager::OnVisibilityChanged(
+    content::WebContents* web_contents) {
+  MaybeChangeOnScreenRestrictions();
 }
 
 void DlpContentManager::RemoveFromConfidential(
     const content::WebContents* web_contents) {
   confidential_web_contents_.erase(web_contents);
-  MaybeChangeVisibilityFlag();
+  MaybeChangeOnScreenRestrictions();
 }
 
-void DlpContentManager::MaybeChangeVisibilityFlag() {
-  bool is_confidential_web_contents_currently_visible = false;
-  for (auto* web_contents : confidential_web_contents_) {
-    if (web_contents->GetVisibility() == content::Visibility::VISIBLE) {
-      is_confidential_web_contents_currently_visible = true;
-      break;
+void DlpContentManager::MaybeChangeOnScreenRestrictions() {
+  DlpContentRestrictionSet new_restriction_set;
+  // TODO(crbug/1111860): Recalculate more effectively.
+  for (const auto& entry : confidential_web_contents_) {
+    if (entry.first->GetVisibility() == content::Visibility::VISIBLE) {
+      new_restriction_set.UnionWith(entry.second);
     }
   }
-  if (is_confidential_web_contents_visible_ !=
-      is_confidential_web_contents_currently_visible) {
-    is_confidential_web_contents_visible_ =
-        is_confidential_web_contents_currently_visible;
-    OnScreenConfidentialityStateChanged(is_confidential_web_contents_visible_);
+  if (on_screen_restrictions_ != new_restriction_set) {
+    on_screen_restrictions_ = new_restriction_set;
+    OnScreenRestrictionsChanged(on_screen_restrictions_);
   }
 }
 
-void DlpContentManager::OnScreenConfidentialityStateChanged(bool visible) {
+void DlpContentManager::OnScreenRestrictionsChanged(
+    const DlpContentRestrictionSet& restrictions) const {
   // TODO(crbug/1105991): Implement enforcing/releasing of restrictions.
 }
 
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
index 3a353f8..750655d 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
@@ -5,7 +5,8 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_MANAGER_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_MANAGER_H_
 
-#include "base/containers/flat_set.h"
+#include "base/containers/flat_map.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
 
 class GURL;
 
@@ -25,13 +26,14 @@
   // There will always be a single instance created on the first access.
   static DlpContentManager* Get();
 
-  // Checks whether |web_contents| is confidential according to the policy.
-  bool IsWebContentsConfidential(
+  // Returns which restrictions are applied to the |web_contents| according to
+  // the policy.
+  DlpContentRestrictionSet GetConfidentialRestrictions(
       const content::WebContents* web_contents) const;
 
-  // Returns whether any WebContents with a confidential content is currently
-  // visible.
-  bool IsConfidentialDataPresentOnScreen() const;
+  // Returns which restrictions are applied to the WebContents which are
+  // currently visible.
+  DlpContentRestrictionSet GetOnScreenPresentRestrictions() const;
 
   // The caller (test) should manage |dlp_content_manager| lifetime.
   // Reset doesn't delete the object.
@@ -52,34 +54,35 @@
   // Called from DlpContentTabHelper:
   // Being called when confidentiality state changes for |web_contents|, e.g.
   // because of navigation.
-  virtual void OnConfidentialityChanged(content::WebContents* web_contents,
-                                        bool confidential);
+  virtual void OnConfidentialityChanged(
+      content::WebContents* web_contents,
+      const DlpContentRestrictionSet& restriction_set);
   // Called when |web_contents| is about to be destroyed.
   virtual void OnWebContentsDestroyed(const content::WebContents* web_contents);
-  // Should return whether |url| is considered as confidential according to
-  // the policies.
-  virtual bool IsURLConfidential(const GURL& url) const;
+  // Should return which restrictions are being applied to the |url| according
+  // to the policies.
+  virtual DlpContentRestrictionSet GetRestrictionSetForURL(
+      const GURL& url) const;
   // Called when |web_contents| becomes visible or not.
-  virtual void OnVisibilityChanged(content::WebContents* web_contents,
-                                   bool visible);
+  virtual void OnVisibilityChanged(content::WebContents* web_contents);
 
-  // Helpers to add/remove WebContents from confidential sets.
-  void AddToConfidential(content::WebContents* web_contents);
+  // Helper to remove |web_contents| from the confidential set.
   void RemoveFromConfidential(const content::WebContents* web_contents);
 
-  // Updates |is_confidential_web_contents_visible_| and calls
-  // OnScreenConfidentialityStateChanged() if needed.
-  void MaybeChangeVisibilityFlag();
+  // Updates |on_screen_restrictions_| and calls
+  // OnScreenRestrictionsChanged() if needed.
+  void MaybeChangeOnScreenRestrictions();
 
-  // Called when a confidential content becomes visible or all confidential
-  // content becomes not visible.
-  void OnScreenConfidentialityStateChanged(bool visible);
+  // Called when the restrictions for currently visible content changes.
+  void OnScreenRestrictionsChanged(
+      const DlpContentRestrictionSet& restrictions) const;
 
-  // Set of currently known confidential WebContents.
-  base::flat_set<content::WebContents*> confidential_web_contents_;
-  // Flag the indicates whether any confidential WebContents is currently
-  // visible or not.
-  bool is_confidential_web_contents_visible_ = false;
+  // Map from currently known confidential WebContents to the restrictions.
+  base::flat_map<content::WebContents*, DlpContentRestrictionSet>
+      confidential_web_contents_;
+
+  // Set of restriction applied to the currently visible content.
+  DlpContentRestrictionSet on_screen_restrictions_;
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_unittest.cc
index b3cc879..e8ba3cd 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_unittest.cc
@@ -12,6 +12,12 @@
 
 namespace policy {
 
+namespace {
+const DlpContentRestrictionSet kEmptyRestrictionSet;
+const DlpContentRestrictionSet kNonEmptyRestrictionSet(
+    DlpContentRestriction::kScreenshot);
+}  // namespace
+
 class DlpContentManagerTest : public testing::Test {
  protected:
   void SetUp() override {
@@ -26,8 +32,8 @@
   }
 
   void ChangeConfidentiality(content::WebContents* web_contents,
-                             bool confidential) {
-    manager_.OnConfidentialityChanged(web_contents, confidential);
+                             DlpContentRestrictionSet restrictions) {
+    manager_.OnConfidentialityChanged(web_contents, restrictions);
   }
 
   void ChangeVisibility(content::WebContents* web_contents, bool visible) {
@@ -36,7 +42,7 @@
     } else {
       web_contents->WasHidden();
     }
-    manager_.OnVisibilityChanged(web_contents, visible);
+    manager_.OnVisibilityChanged(web_contents);
   }
 
   void DestroyWebContents(content::WebContents* web_contents) {
@@ -53,89 +59,114 @@
 
 TEST_F(DlpContentManagerTest, NoConfidentialDataShown) {
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 }
 
 TEST_F(DlpContentManagerTest, ConfidentialDataShown) {
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 
-  ChangeConfidentiality(web_contents.get(), /*confidential=*/true);
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_TRUE(manager_.IsConfidentialDataPresentOnScreen());
+  ChangeConfidentiality(web_contents.get(), kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kNonEmptyRestrictionSet);
 
   DestroyWebContents(web_contents.get());
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 }
 
 TEST_F(DlpContentManagerTest, ConfidentialDataVisibilityChanged) {
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 
-  ChangeConfidentiality(web_contents.get(), /*confidential=*/true);
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_TRUE(manager_.IsConfidentialDataPresentOnScreen());
+  ChangeConfidentiality(web_contents.get(), kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kNonEmptyRestrictionSet);
 
+  web_contents->WasHidden();
   ChangeVisibility(web_contents.get(), /*visible=*/false);
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 
+  web_contents->WasShown();
   ChangeVisibility(web_contents.get(), /*visible=*/true);
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_TRUE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kNonEmptyRestrictionSet);
 
   DestroyWebContents(web_contents.get());
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 }
 
 TEST_F(DlpContentManagerTest,
        TwoWebContentsVisibilityAndConfidentialityChanged) {
   std::unique_ptr<content::WebContents> web_contents1 = CreateWebContents();
   std::unique_ptr<content::WebContents> web_contents2 = CreateWebContents();
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 
   // WebContents 1 becomes confidential.
-  ChangeConfidentiality(web_contents1.get(), /*confidential=*/true);
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_TRUE(manager_.IsConfidentialDataPresentOnScreen());
+  ChangeConfidentiality(web_contents1.get(), kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kNonEmptyRestrictionSet);
 
   // WebContents 2 is hidden.
   ChangeVisibility(web_contents2.get(), /*visible=*/false);
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_TRUE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kNonEmptyRestrictionSet);
 
   // WebContents 1 becomes non-confidential.
-  ChangeConfidentiality(web_contents1.get(), /*confidential=*/false);
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  ChangeConfidentiality(web_contents1.get(), kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 
   // WebContents 2 becomes confidential.
-  ChangeConfidentiality(web_contents2.get(), /*confidential=*/true);
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  ChangeConfidentiality(web_contents2.get(), kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 
   // WebContents 2 is visible.
   ChangeVisibility(web_contents2.get(), /*visible=*/true);
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_TRUE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_TRUE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kNonEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kNonEmptyRestrictionSet);
 
   DestroyWebContents(web_contents1.get());
   DestroyWebContents(web_contents2.get());
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents1.get()));
-  EXPECT_FALSE(manager_.IsWebContentsConfidential(web_contents2.get()));
-  EXPECT_FALSE(manager_.IsConfidentialDataPresentOnScreen());
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents1.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetConfidentialRestrictions(web_contents2.get()),
+            kEmptyRestrictionSet);
+  EXPECT_EQ(manager_.GetOnScreenPresentRestrictions(), kEmptyRestrictionSet);
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc
new file mode 100644
index 0000000..7464e24
--- /dev/null
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.cc
@@ -0,0 +1,57 @@
+// 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 "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
+
+namespace policy {
+
+DlpContentRestrictionSet::DlpContentRestrictionSet() = default;
+
+DlpContentRestrictionSet::DlpContentRestrictionSet(
+    DlpContentRestriction restriction)
+    : restriction_mask_(restriction) {}
+
+DlpContentRestrictionSet::DlpContentRestrictionSet(
+    const DlpContentRestrictionSet& restriction_set) = default;
+
+DlpContentRestrictionSet& DlpContentRestrictionSet::operator=(
+    const DlpContentRestrictionSet&) = default;
+
+DlpContentRestrictionSet::~DlpContentRestrictionSet() = default;
+
+bool DlpContentRestrictionSet::operator==(
+    const DlpContentRestrictionSet& other) const {
+  return restriction_mask_ == other.restriction_mask_;
+}
+
+bool DlpContentRestrictionSet::operator!=(
+    const DlpContentRestrictionSet& other) const {
+  return !(*this == other);
+}
+
+void DlpContentRestrictionSet::SetRestriction(
+    DlpContentRestriction restriction) {
+  restriction_mask_ |= restriction;
+}
+
+bool DlpContentRestrictionSet::HasRestriction(
+    DlpContentRestriction restriction) const {
+  return (restriction_mask_ & restriction) != 0;
+}
+
+void DlpContentRestrictionSet::UnionWith(
+    const DlpContentRestrictionSet& other) {
+  restriction_mask_ |= other.restriction_mask_;
+}
+
+DlpContentRestrictionSet DlpContentRestrictionSet::DifferenceWith(
+    const DlpContentRestrictionSet& other) const {
+  // Leave only the restrictions that are present in |this|, but not in |other|.
+  return DlpContentRestrictionSet(restriction_mask_ & ~other.restriction_mask_);
+}
+
+DlpContentRestrictionSet::DlpContentRestrictionSet(uint8_t mask)
+    : restriction_mask_(mask) {}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h
new file mode 100644
index 0000000..eb95143
--- /dev/null
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h
@@ -0,0 +1,62 @@
+// 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 CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_RESTRICTION_SET_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_RESTRICTION_SET_H_
+
+#include <stdint.h>
+
+namespace policy {
+
+// Enum representing the possible restrictions applied to on-screen content.
+// These values are used in bitmask in DlpContentRestrictionSet and should
+// correspond to the type in which the mask is stored.
+enum DlpContentRestriction {
+  // Do not allow any screenshots of the corresponding content.
+  kScreenshot = 1 << 0,
+};
+
+// Represents set of restrictions applied to on-screen content.
+// Internally stores it in a single integer bitmask.
+// Allowed to be copied and assigned.
+class DlpContentRestrictionSet {
+ public:
+  DlpContentRestrictionSet();
+  explicit DlpContentRestrictionSet(DlpContentRestriction restriction);
+
+  DlpContentRestrictionSet(const DlpContentRestrictionSet& restriction_set);
+  DlpContentRestrictionSet& operator=(const DlpContentRestrictionSet&);
+
+  ~DlpContentRestrictionSet();
+
+  bool operator==(const DlpContentRestrictionSet& other) const;
+  bool operator!=(const DlpContentRestrictionSet& other) const;
+
+  // Adds the restriction to the set if not yet.
+  void SetRestriction(DlpContentRestriction restriction);
+
+  // Returns whether the restriction is present in the set.
+  bool HasRestriction(DlpContentRestriction restriction) const;
+
+  // Returns whether no restrictions should be applied.
+  bool IsEmpty() const { return restriction_mask_ == 0; }
+
+  // Adds all the restrictions from |other| to this.
+  void UnionWith(const DlpContentRestrictionSet& other);
+
+  // Returns a new set that contains restrictions that exist in this, but not in
+  // |other|.
+  DlpContentRestrictionSet DifferenceWith(
+      const DlpContentRestrictionSet& other) const;
+
+ private:
+  explicit DlpContentRestrictionSet(uint8_t mask);
+
+  // Bitmask of the restrictions.
+  uint8_t restriction_mask_ = 0;
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_RESTRICTION_SET_H_
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc
index e5945a6..b0614f22 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.cc
@@ -16,44 +16,29 @@
 
 void DlpContentTabHelper::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
-  if (DlpContentManager::Get()->IsURLConfidential(
-          render_frame_host->GetLastCommittedURL())) {
-    const bool inserted = confidential_frames_.insert(render_frame_host).second;
-    if (inserted && confidential_frames_.size() == 1) {
-      DlpContentManager::Get()->OnConfidentialityChanged(web_contents(),
-                                                         /*confidential=*/true);
-    }
-  }
+  const DlpContentRestrictionSet restriction_set =
+      DlpContentManager::Get()->GetRestrictionSetForURL(
+          render_frame_host->GetLastCommittedURL());
+  if (!restriction_set.IsEmpty())
+    AddFrame(render_frame_host, restriction_set);
 }
 
 void DlpContentTabHelper::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
-  const bool erased = confidential_frames_.erase(render_frame_host);
-  if (erased && confidential_frames_.empty())
-    DlpContentManager::Get()->OnConfidentialityChanged(web_contents(),
-                                                       /*confidential=*/false);
+  RemoveFrame(render_frame_host);
 }
 
 void DlpContentTabHelper::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage())
     return;
-  if (DlpContentManager::Get()->IsURLConfidential(
-          navigation_handle->GetURL())) {
-    const bool inserted =
-        confidential_frames_.insert(navigation_handle->GetRenderFrameHost())
-            .second;
-    if (inserted && confidential_frames_.size() == 1) {
-      DlpContentManager::Get()->OnConfidentialityChanged(web_contents(),
-                                                         /*confidential=*/true);
-    }
+  const DlpContentRestrictionSet restriction_set =
+      DlpContentManager::Get()->GetRestrictionSetForURL(
+          navigation_handle->GetURL());
+  if (restriction_set.IsEmpty()) {
+    RemoveFrame(navigation_handle->GetRenderFrameHost());
   } else {
-    const bool erased =
-        confidential_frames_.erase(navigation_handle->GetRenderFrameHost());
-    if (erased && confidential_frames_.empty())
-      DlpContentManager::Get()->OnConfidentialityChanged(
-          web_contents(),
-          /*confidential=*/false);
+    AddFrame(navigation_handle->GetRenderFrameHost(), restriction_set);
   }
 }
 
@@ -63,17 +48,42 @@
 
 void DlpContentTabHelper::OnVisibilityChanged(content::Visibility visibility) {
   // DlpContentManager tracks visibility only for confidential WebContents.
-  if (!IsConfidential())
+  if (GetRestrictionSet().IsEmpty())
     return;
-  DlpContentManager::Get()->OnVisibilityChanged(
-      web_contents(), visibility == content::Visibility::VISIBLE);
+  DlpContentManager::Get()->OnVisibilityChanged(web_contents());
 }
 
 DlpContentTabHelper::DlpContentTabHelper(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents) {}
 
-bool DlpContentTabHelper::IsConfidential() const {
-  return !confidential_frames_.empty();
+DlpContentRestrictionSet DlpContentTabHelper::GetRestrictionSet() const {
+  DlpContentRestrictionSet set;
+  for (auto& entry : confidential_frames_) {
+    set.UnionWith(entry.second);
+  }
+  return set;
+}
+
+void DlpContentTabHelper::AddFrame(content::RenderFrameHost* render_frame_host,
+                                   DlpContentRestrictionSet restrictions) {
+  const DlpContentRestrictionSet old_restriction_set = GetRestrictionSet();
+  confidential_frames_[render_frame_host] = restrictions;
+  const DlpContentRestrictionSet new_restriction_set = GetRestrictionSet();
+  if (new_restriction_set != old_restriction_set) {
+    DlpContentManager::Get()->OnConfidentialityChanged(web_contents(),
+                                                       new_restriction_set);
+  }
+}
+
+void DlpContentTabHelper::RemoveFrame(
+    content::RenderFrameHost* render_frame_host) {
+  const DlpContentRestrictionSet old_restriction_set = GetRestrictionSet();
+  confidential_frames_.erase(render_frame_host);
+  const DlpContentRestrictionSet new_restriction_set = GetRestrictionSet();
+  if (old_restriction_set != new_restriction_set) {
+    DlpContentManager::Get()->OnConfidentialityChanged(web_contents(),
+                                                       new_restriction_set);
+  }
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(DlpContentTabHelper)
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.h b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.h
index bffff1f..0a22b26 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.h
@@ -5,7 +5,8 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_TAB_HELPER_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_TAB_HELPER_H_
 
-#include "base/containers/flat_set.h"
+#include "base/containers/flat_map.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
 #include "content/public/browser/visibility.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -24,6 +25,8 @@
 // DlpContentManager.
 // WebContents is considered as confidential if either the main frame or any
 // of sub-frames are confidential according to the current policy.
+// In this case the applied restrictions for the WebContents will be the
+// superset of all restrictions for sub-frames.
 class DlpContentTabHelper
     : public content::WebContentsUserData<DlpContentTabHelper>,
       public content::WebContentsObserver {
@@ -45,12 +48,22 @@
   DlpContentTabHelper(const DlpContentTabHelper&) = delete;
   DlpContentTabHelper& operator=(const DlpContentTabHelper&) = delete;
 
-  // WebContents is considered as confidential if either the main frame or any
-  // of sub-frames are confidential.
-  bool IsConfidential() const;
+  // Returns the superset of all restrictions for sub-frames.
+  DlpContentRestrictionSet GetRestrictionSet() const;
 
-  // Set of the currently known confidential frames.
-  base::flat_set<content::RenderFrameHost*> confidential_frames_;
+  // Adds or updates the |render_frame_host| and |restrictions| to/in the map
+  // and notifies DlpContentManager if needed.
+  void AddFrame(content::RenderFrameHost* render_frame_host,
+                DlpContentRestrictionSet restrictions);
+
+  // Removes |render_frame_host| from the map and notifies DlpContentManager if
+  // needed.
+  void RemoveFrame(content::RenderFrameHost* render_frame_host);
+
+  // Map from the currently known confidential frames to the corresponding
+  // restriction set.
+  base::flat_map<content::RenderFrameHost*, DlpContentRestrictionSet>
+      confidential_frames_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc
index 1bf4eb8..5328866 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc
@@ -19,12 +19,20 @@
 using testing::_;
 using testing::Return;
 
+namespace {
+const DlpContentRestrictionSet kEmptyRestrictionSet;
+const DlpContentRestrictionSet kNonEmptyRestrictionSet(
+    DlpContentRestriction::kScreenshot);
+}  // namespace
+
 class MockDlpContentManager : public DlpContentManager {
  public:
-  MOCK_METHOD2(OnConfidentialityChanged, void(content::WebContents*, bool));
+  MOCK_METHOD2(OnConfidentialityChanged,
+               void(content::WebContents*, const DlpContentRestrictionSet&));
   MOCK_METHOD1(OnWebContentsDestroyed, void(const content::WebContents*));
-  MOCK_CONST_METHOD1(IsURLConfidential, bool(const GURL&));
-  MOCK_METHOD2(OnVisibilityChanged, void(content::WebContents*, bool));
+  MOCK_CONST_METHOD1(GetRestrictionSetForURL,
+                     DlpContentRestrictionSet(const GURL&));
+  MOCK_METHOD1(OnVisibilityChanged, void(content::WebContents*));
 };
 
 class DlpContentTabHelperTest : public ChromeRenderViewHostTestHarness {
@@ -59,17 +67,17 @@
   std::unique_ptr<Browser> browser_;
 };
 
-TEST_F(DlpContentTabHelperTest, SingleNotConfidentialWebContents) {
+TEST_F(DlpContentTabHelperTest, NotConfidential) {
   GURL kUrl = GURL("https://example.com");
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(GURL()))
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(GURL()))
       .Times(1)
-      .WillOnce(Return(false));
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(kUrl))
+      .WillOnce(Return(kEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(kUrl))
       .Times(1)
-      .WillOnce(Return(false));
+      .WillOnce(Return(kEmptyRestrictionSet));
   EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, _))
       .Times(0);
-  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_, _)).Times(0);
+  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_)).Times(0);
 
   content::WebContents* web_contents =
       tab_activity_simulator_.AddWebContentsAndNavigate(tab_strip_model_, kUrl);
@@ -78,42 +86,44 @@
   EXPECT_CALL(mock_dlp_content_manager_, OnWebContentsDestroyed(_)).Times(1);
 }
 
-TEST_F(DlpContentTabHelperTest, SingleConfidentialWebContents) {
+TEST_F(DlpContentTabHelperTest, Confidential) {
   GURL kUrl = GURL("https://example.com");
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(GURL()))
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(GURL()))
       .Times(1)
-      .WillOnce(Return(false));
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(kUrl))
+      .WillOnce(Return(kEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(kUrl))
       .Times(1)
-      .WillOnce(Return(true));
-  EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, true))
+      .WillOnce(Return(kNonEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_,
+              OnConfidentialityChanged(_, kNonEmptyRestrictionSet))
       .Times(1);
-  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_, _)).Times(0);
+  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_)).Times(0);
 
   content::WebContents* web_contents =
       tab_activity_simulator_.AddWebContentsAndNavigate(tab_strip_model_, kUrl);
   EXPECT_NE(nullptr, DlpContentTabHelper::FromWebContents(web_contents));
 
-  EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, false))
+  EXPECT_CALL(mock_dlp_content_manager_,
+              OnConfidentialityChanged(_, kEmptyRestrictionSet))
       .Times(1);
   EXPECT_CALL(mock_dlp_content_manager_, OnWebContentsDestroyed(_)).Times(1);
 }
 
-TEST_F(DlpContentTabHelperTest, TwoWebContentsVisibilityChanged) {
+TEST_F(DlpContentTabHelperTest, VisibilityChanged) {
   GURL kUrl1 = GURL("https://example1.com");
   GURL kUrl2 = GURL("https://example2.com");
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(GURL()))
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(kUrl1))
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(GURL()))
+      .WillRepeatedly(Return(kEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(kUrl1))
       .Times(1)
-      .WillOnce(Return(true));
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(kUrl2))
+      .WillOnce(Return(kNonEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(kUrl2))
       .Times(1)
-      .WillOnce(Return(false));
-  EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, true))
+      .WillOnce(Return(kEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_,
+              OnConfidentialityChanged(_, kNonEmptyRestrictionSet))
       .Times(1);
-  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_, _)).Times(0);
-
+  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_)).Times(0);
   content::WebContents* web_contents1 =
       tab_activity_simulator_.AddWebContentsAndNavigate(tab_strip_model_,
                                                         kUrl1);
@@ -122,16 +132,16 @@
                                                         kUrl2);
   EXPECT_NE(nullptr, DlpContentTabHelper::FromWebContents(web_contents1));
   EXPECT_NE(nullptr, DlpContentTabHelper::FromWebContents(web_contents2));
-  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_, false))
-      .Times(1);
+  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_)).Times(1);
 
   tab_activity_simulator_.SwitchToTabAt(tab_strip_model_, 1);
 
-  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_, true)).Times(1);
+  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_)).Times(1);
 
   tab_activity_simulator_.SwitchToTabAt(tab_strip_model_, 0);
 
-  EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, false))
+  EXPECT_CALL(mock_dlp_content_manager_,
+              OnConfidentialityChanged(_, kEmptyRestrictionSet))
       .Times(1);
   EXPECT_CALL(mock_dlp_content_manager_, OnWebContentsDestroyed(_)).Times(2);
 }
@@ -139,15 +149,17 @@
 TEST_F(DlpContentTabHelperTest, SubFrameNavigation) {
   GURL kNonConfidentialUrl = GURL("https://example.com");
   GURL kConfidentialUrl = GURL("https://google.com");
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(GURL()))
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(kNonConfidentialUrl))
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_dlp_content_manager_, IsURLConfidential(kConfidentialUrl))
-      .WillRepeatedly(Return(true));
+  EXPECT_CALL(mock_dlp_content_manager_, GetRestrictionSetForURL(GURL()))
+      .WillRepeatedly(Return(kEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_,
+              GetRestrictionSetForURL(kNonConfidentialUrl))
+      .WillRepeatedly(Return(kEmptyRestrictionSet));
+  EXPECT_CALL(mock_dlp_content_manager_,
+              GetRestrictionSetForURL(kConfidentialUrl))
+      .WillRepeatedly(Return(kNonEmptyRestrictionSet));
   EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, _))
       .Times(0);
-  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_, _)).Times(0);
+  EXPECT_CALL(mock_dlp_content_manager_, OnVisibilityChanged(_)).Times(0);
 
   // Create WebContents.
   content::WebContents* web_contents =
@@ -156,7 +168,8 @@
   EXPECT_NE(nullptr, DlpContentTabHelper::FromWebContents(web_contents));
 
   // Add subframe and navigate to confidential URL.
-  EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, true))
+  EXPECT_CALL(mock_dlp_content_manager_,
+              OnConfidentialityChanged(_, kNonEmptyRestrictionSet))
       .Times(1);
   content::RenderFrameHost* subframe =
       content::NavigationSimulator::NavigateAndCommitFromDocument(
@@ -165,7 +178,8 @@
               ->AppendChild("child"));
 
   // Navigate away from confidential URL.
-  EXPECT_CALL(mock_dlp_content_manager_, OnConfidentialityChanged(_, false))
+  EXPECT_CALL(mock_dlp_content_manager_,
+              OnConfidentialityChanged(_, kEmptyRestrictionSet))
       .Times(1);
   content::NavigationSimulator::NavigateAndCommitFromDocument(
       kNonConfidentialUrl, subframe);
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 665246d..940e9a0 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -2374,7 +2374,9 @@
   DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
 }
 
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DisposeEmptyBrowserContext) {
+// TODO(crbug.com/1110417): Flaky.
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
+                       DISABLED_DisposeEmptyBrowserContext) {
   window_ = DevToolsWindowTesting::OpenDiscoveryDevToolsWindowSync(
       browser()->profile());
   RunTestMethod("testDisposeEmptyBrowserContext");
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index f60932e..8566576e 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -873,22 +873,27 @@
         base::FilePath() /* profile_path */,
         nullptr /* shared_cors_origin_access_list */);
   } else if (content::HasWebUIScheme(gurl)) {
-    // In debug builds, or when a custom devtools is used, allow retrieving
-    // files from the chrome:// and devtools:// schemes.
-#if defined(NDEBUG)
-    const bool devtools_should_be_debuggable = true;
-#else
-    const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-    const bool devtools_should_be_debuggable =
-        cmd_line->HasSwitch(switches::kCustomDevtoolsFrontend);
-#endif
     content::WebContents* target_tab =
         DevToolsWindow::AsDevToolsWindow(web_contents_)
             ->GetInspectedWebContents();
+#if defined(NDEBUG)
+    // In release builds, allow files from the chrome://, devtools:// and
+    // chrome-untrusted:// schemes if a custom devtools front-end was specified.
+    const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
     const bool allow_web_ui_scheme =
-        devtools_should_be_debuggable && target_tab &&
-        content::HasWebUIScheme(target_tab->GetURL());
-    if (allow_web_ui_scheme) {
+        cmd_line->HasSwitch(switches::kCustomDevtoolsFrontend);
+#else
+    // In debug builds, always allow retrieving files from the chrome://,
+    // devtools:// and chrome-untrusted:// schemes.
+    const bool allow_web_ui_scheme = true;
+#endif
+    // Only allow retrieval if the scheme of the file is the same as the
+    // top-level frame of the inspected page.
+    // TODO(sigurds): Track which frame triggered the load, match schemes to the
+    // committed URL of that frame, and use the loader associated with that
+    // frame to allow nested frames with different schemes to load files.
+    if (allow_web_ui_scheme && target_tab &&
+        target_tab->GetURL().scheme() == gurl.scheme()) {
       std::vector<std::string> allowed_webui_hosts;
       content::RenderFrameHost* frame_host = web_contents()->GetMainFrame();
       url_loader_factory = content::CreateWebUIURLLoader(
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.cc b/chrome/browser/extensions/api/notifications/notifications_api.cc
index 5e865b5..3db3795f 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -12,7 +12,6 @@
 #include "base/callback.h"
 #include "base/guid.h"
 #include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
@@ -253,8 +252,6 @@
   // Extract required fields: type, title, message, and icon.
   message_center::NotificationType type =
       MapApiTemplateTypeToType(options->type);
-  UMA_HISTOGRAM_ENUMERATION("Notifications.ExtensionNotificationType", type,
-                            message_center::NOTIFICATION_TYPE_LAST);
 
   const base::string16 title(base::UTF8ToUTF16(*options->title));
   const base::string16 message(base::UTF8ToUTF16(*options->message));
@@ -294,12 +291,6 @@
     // Currently we allow up to 2 buttons.
     size_t number_of_buttons = options->buttons->size();
 
-    // Use distinct buckets for 1-16 notification action buttons, and an
-    // overflow bucket for 17 or more action buttons. Does not impact how many
-    // action buttons are shown.
-    UMA_HISTOGRAM_ENUMERATION("Notifications.ExtensionNotificationActionCount",
-                              number_of_buttons, 17);
-
     number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
 
     for (size_t i = 0; i < number_of_buttons; i++) {
diff --git a/chrome/browser/nearby_sharing/attachment.h b/chrome/browser/nearby_sharing/attachment.h
index caac8ea5..007a496 100644
--- a/chrome/browser/nearby_sharing/attachment.h
+++ b/chrome/browser/nearby_sharing/attachment.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include "base/unguessable_token.h"
+
 // A single attachment to be sent by / received from a ShareTarget, can be
 // either a file or text.
 class Attachment {
@@ -17,6 +19,11 @@
 
   virtual int64_t size() const = 0;
   virtual Family family() const = 0;
+
+  const base::UnguessableToken& id() const { return id_; }
+
+ private:
+  base::UnguessableToken id_ = base::UnguessableToken::Create();
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_ATTACHMENT_H_
diff --git a/chrome/browser/nearby_sharing/attachment_info.cc b/chrome/browser/nearby_sharing/attachment_info.cc
new file mode 100644
index 0000000..92b90207
--- /dev/null
+++ b/chrome/browser/nearby_sharing/attachment_info.cc
@@ -0,0 +1,11 @@
+// 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 "chrome/browser/nearby_sharing/attachment_info.h"
+
+AttachmentInfo::AttachmentInfo() = default;
+AttachmentInfo::~AttachmentInfo() = default;
+
+AttachmentInfo::AttachmentInfo(AttachmentInfo&&) = default;
+AttachmentInfo& AttachmentInfo::operator=(AttachmentInfo&&) = default;
diff --git a/chrome/browser/nearby_sharing/attachment_info.h b/chrome/browser/nearby_sharing/attachment_info.h
new file mode 100644
index 0000000..c83f35d0
--- /dev/null
+++ b/chrome/browser/nearby_sharing/attachment_info.h
@@ -0,0 +1,25 @@
+// 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 CHROME_BROWSER_NEARBY_SHARING_ATTACHMENT_INFO_H_
+#define CHROME_BROWSER_NEARBY_SHARING_ATTACHMENT_INFO_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/optional.h"
+
+// Ties associated information to an Attachment.
+struct AttachmentInfo {
+  AttachmentInfo();
+  ~AttachmentInfo();
+
+  AttachmentInfo(AttachmentInfo&&);
+  AttachmentInfo& operator=(AttachmentInfo&&);
+
+  base::Optional<int64_t> payload_id;
+  std::string text_body;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_ATTACHMENT_INFO_H_
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index a5006b8..6f16066c 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -818,7 +818,7 @@
                     << file->mime_type;
     FileAttachment attachment(file->name, file->type, file->size,
                               /*file_path=*/base::nullopt, file->mime_type);
-    // TODO(himanshujaju) - setAttachmentPayloadId();
+    SetAttachmentPayloadId(attachment, file->payload_id);
     share_target.file_attachments.push_back(std::move(attachment));
   }
 
@@ -834,7 +834,7 @@
     NS_LOG(VERBOSE) << __func__ << "Found text attachment " << text->text_title
                     << " of type " << text->type;
     TextAttachment attachment(text->text_title, text->type, text->size);
-    // TODO(himanshujaju) - setAttachmentPayloadId();
+    SetAttachmentPayloadId(attachment, text->payload_id);
     share_target.text_attachments.push_back(std::move(attachment));
   }
 
@@ -947,3 +947,9 @@
 void NearbySharingServiceImpl::ClearOutgoingShareTargetInfoMap() {
   outgoing_share_target_info_map_.clear();
 }
+
+void NearbySharingServiceImpl::SetAttachmentPayloadId(
+    const Attachment& attachment,
+    int64_t payload_id) {
+  attachment_info_map_[attachment.id()].payload_id = payload_id;
+}
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
index b1abe04..e92b602 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -17,6 +17,8 @@
 #include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "base/unguessable_token.h"
+#include "chrome/browser/nearby_sharing/attachment.h"
+#include "chrome/browser/nearby_sharing/attachment_info.h"
 #include "chrome/browser/nearby_sharing/client/nearby_share_http_notifier.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_enums.h"
 #include "chrome/browser/nearby_sharing/incoming_frames_reader.h"
@@ -158,6 +160,7 @@
   OutgoingShareTargetInfo& GetOutgoingShareTargetInfo(
       const ShareTarget& share_target);
   void ClearOutgoingShareTargetInfoMap();
+  void SetAttachmentPayloadId(const Attachment& attachment, int64_t payload_id);
 
   PrefService* prefs_;
   Profile* profile_;
@@ -199,6 +202,10 @@
   base::flat_map<base::UnguessableToken, OutgoingShareTargetInfo>
       outgoing_share_target_info_map_;
 
+  // A mapping of Attachment Id to additional AttachmentInfo related to the
+  // Attachment.
+  base::flat_map<base::UnguessableToken, AttachmentInfo> attachment_info_map_;
+
   // This alarm is used to disconnect the sharing connection if both sides do
   // not press accept within the timeout.
   base::CancelableOnceClosure mutual_acceptance_timeout_alarm_;
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index 5a63ef3..ce4bdba 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -790,7 +790,9 @@
 // Make sure that a same document navigation does not cause issues with the
 // auto-reload timer.  Note that this test was added due to this case causing
 // a crash.  On regression, this test may hang due to a crashed renderer.
-IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, IgnoresSameDocumentNavigation) {
+// TODO(crbug.com/1111535): Flaky.
+IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest,
+                       DISABLED_IgnoresSameDocumentNavigation) {
   GURL test_url("http://error.page.auto.reload");
   InstallInterceptor(test_url, 2);
 
diff --git a/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc
index da446b0..8b3a46d 100644
--- a/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc
@@ -18,9 +18,12 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 
 namespace {
 
+using UkmEntry = ukm::builders::HistoryNavigation;
+
 class BackForwardCachePageLoadMetricsObserverBrowserTest
     : public MetricIntegrationTest {
  public:
@@ -46,6 +49,46 @@
         web_contents());
   }
 
+  void ExpectMetricValueForUrl(const GURL& url,
+                               const char* metric_name,
+                               const int expected_value) {
+    for (auto* entry : ukm_recorder().GetEntriesByName(UkmEntry::kEntryName)) {
+      // As the source ID is generated from the back-forward restore navigation,
+      // this should not match with the source ID by the ID used by the initial
+      // navigation which loaded the page.
+      DCHECK_NE(top_frame_host()->GetPageUkmSourceId(), entry->source_id);
+
+      auto* source = ukm_recorder().GetSourceForSourceId(entry->source_id);
+      DCHECK(source);
+      if (source->url() != url)
+        continue;
+      if (!ukm_recorder().EntryHasMetric(entry, metric_name))
+        continue;
+      ukm_recorder().ExpectEntryMetric(entry, metric_name, expected_value);
+    }
+  }
+
+  void ExpectMetricCountForUrl(const GURL& url,
+                               const char* metric_name,
+                               const int expected_count) {
+    int count = 0;
+    for (auto* entry : ukm_recorder().GetEntriesByName(UkmEntry::kEntryName)) {
+      // As the source ID is generated from the back-forward restore navigation,
+      // this should not match with the source ID by the ID used by the initial
+      // navigation which loaded the page.
+      DCHECK_NE(top_frame_host()->GetPageUkmSourceId(), entry->source_id);
+
+      auto* source = ukm_recorder().GetSourceForSourceId(entry->source_id);
+      DCHECK(source);
+      if (source->url() != url)
+        continue;
+      if (!ukm_recorder().EntryHasMetric(entry, metric_name))
+        continue;
+      count++;
+    }
+    EXPECT_EQ(count, expected_count);
+  }
+
   base::test::ScopedFeatureList feature_list_;
 };
 
@@ -79,6 +122,8 @@
     waiter->Wait();
     histogram_tester().ExpectTotalCount(
         internal::kHistogramFirstPaintAfterBackForwardCacheRestore, 1);
+    ExpectMetricCountForUrl(
+        url_a, "NavigationToFirstPaintAfterBackForwardCacheRestore", 1);
   }
 
   // The RenderFrameHost for the page B was likely in the back-forward cache
@@ -103,6 +148,8 @@
     waiter->Wait();
     histogram_tester().ExpectTotalCount(
         internal::kHistogramFirstPaintAfterBackForwardCacheRestore, 2);
+    ExpectMetricCountForUrl(
+        url_a, "NavigationToFirstPaintAfterBackForwardCacheRestore", 2);
   }
 }
 
@@ -140,10 +187,12 @@
 
     waiter->Wait();
 
-    // As the tab goes to the background before the first paint, the UMA is not
-    // recorded.
+    // As the tab goes to the background before the first paint, the UMA and the
+    // UKM are not recorded.
     histogram_tester().ExpectTotalCount(
         internal::kHistogramFirstPaintAfterBackForwardCacheRestore, 0);
+    ExpectMetricCountForUrl(
+        url_a, "NavigationToFirstPaintAfterBackForwardCacheRestore", 0);
   }
 }
 
@@ -183,6 +232,8 @@
 
     histogram_tester().ExpectTotalCount(
         internal::kHistogramFirstInputDelayAfterBackForwardCacheRestore, 1);
+    ExpectMetricCountForUrl(url_a,
+                            "FirstInputDelayAfterBackForwardCacheRestore", 1);
   }
 }
 
@@ -232,7 +283,9 @@
 const shifter = document.querySelector('#shifter');
 const currentTop =
   parseInt(getComputedStyle(shifter).getPropertyValue('top'), 10);
-const newTop = 320;
+// With too big newTop (e.g., 320), the calculated score and the actual score
+// can differ probably due to the window height. Use 300 here.
+const newTop = 300;
 shifter.style.top = newTop + 'px';
 const score = computeExpectedScore(
     300 * (200 + newTop - currentTop), newTop - currentTop);
@@ -266,6 +319,10 @@
   histogram_tester().ExpectTotalCount(
       internal::kHistogramCumulativeShiftScoreAfterBackForwardCacheRestore, 1);
 
+  ExpectMetricValueForUrl(url_a,
+                          "CumulativeShiftScoreAfterBackForwardCacheRestore",
+                          page_load_metrics::LayoutShiftUkmValue(next_score));
+
   // Go back to A again.
   web_contents()->GetController().GoBack();
   EXPECT_TRUE(WaitForLoadStop(web_contents()));
@@ -282,4 +339,7 @@
       2);
   histogram_tester().ExpectTotalCount(
       internal::kHistogramCumulativeShiftScoreAfterBackForwardCacheRestore, 2);
+
+  ExpectMetricCountForUrl(
+      url_a, "CumulativeShiftScoreAfterBackForwardCacheRestore", 2);
 }
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java
index ed8b8e58..e78deaf 100644
--- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java
@@ -33,6 +33,19 @@
          * @param credential A {@link CompromisedCredential} to be removed.
          */
         void onRemove(CompromisedCredential credential);
+
+        /**
+         * Opens a password change form or home page of |credential|'s origin or an app.
+         * @param credential A {@link CompromisedCredential} to be changed.
+         */
+        void onChangePasswordButtonClick(CompromisedCredential credential);
+
+        /**
+         * Starts a script to change a {@link CompromisedCredential}. Can be called only if {@link
+         * CompromisedCredential#hasScript()}.
+         * @param credential A {@link CompromisedCredential} to be change with a script.
+         */
+        void onChangePasswordWithScriptButtonClick(CompromisedCredential credential);
     }
 
     PasswordCheckCoordinator(PasswordCheckFragmentView fragmentView) {
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
index 5dd28c63..2b14dda 100644
--- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
@@ -63,4 +63,14 @@
     public void onRemove(CompromisedCredential credential) {
         mDelegate.removeCredential(credential);
     }
+
+    @Override
+    public void onChangePasswordButtonClick(CompromisedCredential credential) {
+        // TODO(crbug.com/1092444): Implement the action for the button.
+    }
+
+    @Override
+    public void onChangePasswordWithScriptButtonClick(CompromisedCredential credential) {
+        // TODO(crbug.com/1086109): Implement the action for the button.
+    }
 }
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java
index 1496562..2d06f4e 100644
--- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java
@@ -28,6 +28,7 @@
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.RecyclerViewAdapter;
 import org.chromium.ui.modelutil.SimpleRecyclerViewMcp;
+import org.chromium.ui.widget.ButtonCompat;
 
 /**
  * Provides functions that map {@link PasswordCheckProperties} changes in a {@link PropertyModel} to
@@ -117,16 +118,24 @@
             reason.setText(credential.isPhished()
                             ? R.string.password_check_credential_row_reason_phished
                             : R.string.password_check_credential_row_reason_leaked);
-            if (credential.hasScript()) {
-                assert view.findViewById(R.id.credential_change_button_with_script) != null;
-                assert view.findViewById(R.id.script_button_explanation) != null;
-            }
 
             ListMenuButton more = view.findViewById(R.id.credential_menu_button);
             more.setDelegate(() -> {
                 return createCredentialMenu(view.getContext(), model.get(COMPROMISED_CREDENTIAL),
                         model.get(CREDENTIAL_HANDLER));
             });
+
+            ButtonCompat button = view.findViewById(R.id.credential_change_button);
+            button.setOnClickListener(unusedView -> {
+                model.get(CREDENTIAL_HANDLER).onChangePasswordButtonClick(credential);
+            });
+            if (credential.hasScript()) {
+                ButtonCompat button_with_script =
+                        view.findViewById(R.id.credential_change_button_with_script);
+                button_with_script.setOnClickListener(unusedView -> {
+                    model.get(CREDENTIAL_HANDLER).onChangePasswordWithScriptButtonClick(credential);
+                });
+            }
         } else if (propertyKey == CREDENTIAL_HANDLER) {
             assert model.get(CREDENTIAL_HANDLER) != null;
             // Is read-only and must therefore be bound initially, so no action required.
diff --git a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java
index a0940ea..6856c7c 100644
--- a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java
+++ b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java
@@ -14,6 +14,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.COMPROMISED_CREDENTIAL;
@@ -40,6 +41,7 @@
 import org.mockito.MockitoAnnotations;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.password_check.PasswordCheck.CheckStatus;
 import org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties;
@@ -48,6 +50,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
 import org.chromium.content_public.browser.test.util.Criteria;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TouchCommon;
 import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -186,6 +189,28 @@
 
     @Test
     @MediumTest
+    public void testClickingChangePasswordTriggersHandler() {
+        runOnUiThreadBlocking(() -> mModel.get(ITEMS).add(buildCredentialItem(ANA)));
+        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+
+        TouchCommon.singleClickView(getCredentialChangeButtonAt(0));
+
+        waitForEvent(mMockHandler).onChangePasswordButtonClick(eq(ANA));
+    }
+
+    @Test
+    @MediumTest
+    public void testClickingChangePasswordWithScriptTriggersHandler() {
+        runOnUiThreadBlocking(() -> mModel.get(ITEMS).add(buildCredentialItem(SCRIPTED)));
+        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+
+        TouchCommon.singleClickView(getCredentialChangeButtonWithScriptAt(0));
+
+        waitForEvent(mMockHandler).onChangePasswordWithScriptButtonClick(eq(SCRIPTED));
+    }
+
+    @Test
+    @MediumTest
     public void testClickingDeleteInMoreMenuTriggersHandler() {
         runOnUiThreadBlocking(() -> mModel.get(ITEMS).add(buildCredentialItem(ANA)));
         pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
@@ -272,4 +297,9 @@
     private String getString(@IdRes int stringResource) {
         return mTestRule.getActivity().getString(stringResource);
     }
+
+    private static <T> T waitForEvent(T mock) {
+        return verify(mock,
+                timeout(ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
+    }
 }
diff --git a/chrome/browser/profiles/profile_attributes_entry.cc b/chrome/browser/profiles/profile_attributes_entry.cc
index 6b79bd1c..8d1db485 100644
--- a/chrome/browser/profiles/profile_attributes_entry.cc
+++ b/chrome/browser/profiles/profile_attributes_entry.cc
@@ -6,6 +6,7 @@
 
 #include "base/hash/hash.h"
 #include "base/logging.h"
+#include "base/notreached.h"
 #include "base/optional.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -25,11 +26,16 @@
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/native_theme/native_theme.h"
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
 #endif
 
+#if !defined(OS_ANDROID)
+#include "chrome/browser/themes/theme_properties.h"
+#endif
+
 namespace {
 
 const char kGAIAGivenNameKey[] = "gaia_given_name";
@@ -410,8 +416,7 @@
   return icon_index;
 }
 
-base::Optional<ProfileThemeColors>
-ProfileAttributesEntry::GetProfileThemeColors() const {
+ProfileThemeColors ProfileAttributesEntry::GetProfileThemeColors() const {
   base::Optional<SkColor> profile_highlight_color =
       GetProfileThemeColor(kProfileHighlightColorKey);
   base::Optional<SkColor> default_avatar_fill_color =
@@ -421,7 +426,8 @@
   if (!profile_highlight_color.has_value()) {
     DCHECK(!default_avatar_fill_color.has_value() &&
            !default_avatar_stroke_color.has_value());
-    return base::nullopt;
+    return GetDefaultProfileThemeColors(
+        ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors());
   }
 
   DCHECK(default_avatar_fill_color.has_value() &&
@@ -665,6 +671,27 @@
   return index;
 }
 
+// static
+ProfileThemeColors ProfileAttributesEntry::GetDefaultProfileThemeColors(
+    bool dark_mode) {
+#if defined(OS_ANDROID)
+  // Profile theme colors shouldn't be queried on Android.
+  NOTREACHED();
+  return {SK_ColorRED, SK_ColorRED, SK_ColorRED};
+#else
+  ProfileThemeColors default_colors;
+  // TODO(https://crbug.com/1102384): update this with the right colors, once we
+  // have them.
+  default_colors.profile_highlight_color = ThemeProperties::GetDefaultColor(
+      ThemeProperties::COLOR_FRAME_ACTIVE, /*incognito=*/false, dark_mode);
+  default_colors.default_avatar_fill_color = ThemeProperties::GetDefaultColor(
+      ThemeProperties::COLOR_FRAME_ACTIVE, /*incognito=*/false, dark_mode);
+  default_colors.default_avatar_stroke_color = ThemeProperties::GetDefaultColor(
+      ThemeProperties::COLOR_TOOLBAR, /*incognito=*/false, dark_mode);
+  return default_colors;
+#endif
+}
+
 const gfx::Image* ProfileAttributesEntry::GetHighResAvatar() const {
   const size_t avatar_index = GetAvatarIconIndex();
 
diff --git a/chrome/browser/profiles/profile_attributes_entry.h b/chrome/browser/profiles/profile_attributes_entry.h
index 36426b2..a5badce 100644
--- a/chrome/browser/profiles/profile_attributes_entry.h
+++ b/chrome/browser/profiles/profile_attributes_entry.h
@@ -142,9 +142,9 @@
   bool IsSignedInWithCredentialProvider() const;
   // Returns the index of the default icon used by the profile.
   size_t GetAvatarIconIndex() const;
-  // Returns the colors specified by the profile theme. base::nullopt indicates
-  // the default colors should be used for this profile.
-  base::Optional<ProfileThemeColors> GetProfileThemeColors() const;
+  // Returns the colors specified by the profile theme, or default colors if no
+  // theme is specified for the profile.
+  ProfileThemeColors GetProfileThemeColors() const;
   // Returns the metrics bucket this profile should be recorded in.
   // Note: The bucket index is assigned once and remains the same all time. 0 is
   // reserved for the guest profile.
@@ -175,6 +175,7 @@
   void SetIsUsingDefaultAvatar(bool value);
   void SetIsAuthError(bool value);
   void SetAvatarIconIndex(size_t icon_index);
+  // base::nullopt resets colors to default.
   void SetProfileThemeColors(const base::Optional<ProfileThemeColors>& colors);
 
   // Unlike for other string setters, the argument is expected to be UTF8
@@ -215,11 +216,15 @@
 
  private:
   friend class ProfileInfoCache;
+  friend class ProfileThemeUpdateServiceBrowserTest;
   FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
                            EntryInternalAccessors);
   FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest, ProfileActiveTime);
   FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
                            DownloadHighResAvatarTest);
+  FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest, ProfileThemeColors);
+
+  static ProfileThemeColors GetDefaultProfileThemeColors(bool dark_mode);
 
   void Initialize(ProfileInfoCache* cache,
                   const base::FilePath& path,
diff --git a/chrome/browser/profiles/profile_attributes_storage_unittest.cc b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
index 19a97d2..f3421e8 100644
--- a/chrome/browser/profiles/profile_attributes_storage_unittest.cc
+++ b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
@@ -29,6 +29,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/native_theme/native_theme.h"
 
 using ::testing::Mock;
 using ::testing::_;
@@ -915,6 +916,8 @@
       "Profile.State.LastUsed_LatentMultiProfileOthers", 0);
 }
 
+// Themes aren't used on Android
+#if !defined(OS_ANDROID)
 TEST_F(ProfileAttributesStorageTest, ProfileThemeColors) {
   AddTestingProfile();
   base::FilePath profile_path = GetProfilePath("testing_profile_path0");
@@ -923,16 +926,27 @@
 
   ProfileAttributesEntry* entry;
   ASSERT_TRUE(storage()->GetProfileAttributesWithPath(profile_path, &entry));
-  EXPECT_EQ(base::nullopt, entry->GetProfileThemeColors());
+  EXPECT_EQ(entry->GetProfileThemeColors(),
+            ProfileAttributesEntry::GetDefaultProfileThemeColors(false));
+
+  ui::NativeTheme::GetInstanceForNativeUi()->set_use_dark_colors(true);
+  EXPECT_EQ(entry->GetProfileThemeColors(),
+            ProfileAttributesEntry::GetDefaultProfileThemeColors(true));
+  EXPECT_NE(entry->GetProfileThemeColors(),
+            ProfileAttributesEntry::GetDefaultProfileThemeColors(false));
 
   ProfileThemeColors colors = {SK_ColorTRANSPARENT, SK_ColorBLACK,
                                SK_ColorWHITE};
   entry->SetProfileThemeColors(colors);
-  base::Optional<ProfileThemeColors> actual_colors =
-      entry->GetProfileThemeColors();
-  ASSERT_TRUE(actual_colors.has_value());
-  EXPECT_EQ(colors, actual_colors);
+  EXPECT_EQ(entry->GetProfileThemeColors(), colors);
 
+  // Colors shouldn't change after switching back to the light mode.
+  ui::NativeTheme::GetInstanceForNativeUi()->set_use_dark_colors(false);
+  EXPECT_EQ(entry->GetProfileThemeColors(), colors);
+
+  // base::nullopt resets the colors to default.
   entry->SetProfileThemeColors(base::nullopt);
-  EXPECT_EQ(base::nullopt, entry->GetProfileThemeColors());
+  EXPECT_EQ(entry->GetProfileThemeColors(),
+            ProfileAttributesEntry::GetDefaultProfileThemeColors(false));
 }
+#endif
diff --git a/chrome/browser/profiles/profile_theme_update_service_browsertest.cc b/chrome/browser/profiles/profile_theme_update_service_browsertest.cc
index f60ee2f..403a210 100644
--- a/chrome/browser/profiles/profile_theme_update_service_browsertest.cc
+++ b/chrome/browser/profiles/profile_theme_update_service_browsertest.cc
@@ -37,6 +37,10 @@
     return entry;
   }
 
+  ProfileThemeColors GetDefaultProfileThemeColors() {
+    return ProfileAttributesEntry::GetDefaultProfileThemeColors(false);
+  }
+
   ThemeService* theme_service() {
     return ThemeServiceFactory::GetForProfile(browser()->profile());
   }
@@ -49,37 +53,41 @@
 // is set up.
 IN_PROC_BROWSER_TEST_F(ProfileThemeUpdateServiceBrowserTest,
                        PRE_AutogeneratedTheme) {
-  EXPECT_FALSE(
-      GetProfileAttributesEntry()->GetProfileThemeColors().has_value());
+  EXPECT_EQ(GetProfileAttributesEntry()->GetProfileThemeColors(),
+            GetDefaultProfileThemeColors());
 
   theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorDKGRAY);
-  base::Optional<ProfileThemeColors> theme_colors =
+  ProfileThemeColors theme_colors =
       GetProfileAttributesEntry()->GetProfileThemeColors();
-  EXPECT_TRUE(theme_colors.has_value());
+  EXPECT_NE(theme_colors, GetDefaultProfileThemeColors());
 
   // Check that a switch to another autogenerated theme updates the colors.
   theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorMAGENTA);
-  base::Optional<ProfileThemeColors> theme_colors2 =
+  ProfileThemeColors theme_colors2 =
       GetProfileAttributesEntry()->GetProfileThemeColors();
-  EXPECT_TRUE(theme_colors2.has_value());
   EXPECT_NE(theme_colors, theme_colors2);
+  EXPECT_NE(theme_colors, GetDefaultProfileThemeColors());
 
   // Reset the cached colors to test that they're recreated on the next startup.
   GetProfileAttributesEntry()->SetProfileThemeColors(base::nullopt);
+  EXPECT_EQ(GetProfileAttributesEntry()->GetProfileThemeColors(),
+            GetDefaultProfileThemeColors());
 }
 
 // Tests that the profile theme colors are updated on startup.
 IN_PROC_BROWSER_TEST_F(ProfileThemeUpdateServiceBrowserTest,
                        AutogeneratedTheme) {
-  EXPECT_TRUE(GetProfileAttributesEntry()->GetProfileThemeColors().has_value());
+  EXPECT_NE(GetProfileAttributesEntry()->GetProfileThemeColors(),
+            GetDefaultProfileThemeColors());
 }
 
 // Tests that switching to the default theme resets the colors.
 IN_PROC_BROWSER_TEST_F(ProfileThemeUpdateServiceBrowserTest, DefaultTheme) {
   theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorDKGRAY);
-  EXPECT_TRUE(GetProfileAttributesEntry()->GetProfileThemeColors().has_value());
+  EXPECT_NE(GetProfileAttributesEntry()->GetProfileThemeColors(),
+            GetDefaultProfileThemeColors());
 
   theme_service()->UseDefaultTheme();
-  EXPECT_FALSE(
-      GetProfileAttributesEntry()->GetProfileThemeColors().has_value());
+  EXPECT_EQ(GetProfileAttributesEntry()->GetProfileThemeColors(),
+            GetDefaultProfileThemeColors());
 }
diff --git a/chrome/browser/resources/settings/autofill_page/password_check.html b/chrome/browser/resources/settings/autofill_page/password_check.html
index 63d0370..617b9ccb 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check.html
+++ b/chrome/browser/resources/settings/autofill_page/password_check.html
@@ -132,7 +132,7 @@
       </button>
       <button id="menuEditPassword" class="dropdown-item"
           on-click="onEditPasswordClick_">
-        $i18n{editCompromisedPassword}
+        $i18n{editPassword}
       </button>
       <button id="menuRemovePassword" class="dropdown-item"
           on-click="onMenuRemovePasswordClick_">
diff --git a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html
index eae831f4..8ec1aad3 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html
@@ -19,7 +19,7 @@
 
     </style>
     <cr-dialog id="dialog" close-text="$i18n{close}">
-      <div slot="title">$i18n{editCompromisedPasswordTitle}</div>
+      <div slot="title">$i18n{editPasswordTitle}</div>
       <div slot="body">
         <cr-input value="[[item.detailedOrigin]]" readonly
             label="[[getSiteOrApp_(item.isAndroidCredential)]]">
diff --git a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js
index 1c25550..83bec206 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js
+++ b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js
@@ -134,8 +134,7 @@
    * @return {string} The text to be displayed as the dialog's footnote.
    */
   getFootnote_() {
-    return this.i18n(
-        'editCompromisedPasswordFootnote', this.item.formattedOrigin);
+    return this.i18n('editPasswordFootnote', this.item.formattedOrigin);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/autofill_page/password_check_edit_disclaimer_dialog.html b/chrome/browser/resources/settings/autofill_page/password_check_edit_disclaimer_dialog.html
index 2a940d4..9076318 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check_edit_disclaimer_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/password_check_edit_disclaimer_dialog.html
@@ -6,7 +6,7 @@
           $i18n{cancel}
         </cr-button>
         <cr-button id="edit" class="action-button" on-click="onEditClick_">
-          $i18n{editCompromisedPassword}
+          $i18n{editPassword}
         </cr-button>
       </div>
     </cr-dialog>
diff --git a/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js b/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js
index c63cac4e..23c7f1d2 100644
--- a/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js
+++ b/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js
@@ -143,9 +143,7 @@
    * @private
    */
   getTitle_() {
-    // TODO(crbug.com/377410): Change strings like
-    // 'editCompromisedPasswordTitle' to 'editPasswordTitle'.
-    return this.isEditDialog_ ? this.i18n('editCompromisedPasswordTitle') :
+    return this.isEditDialog_ ? this.i18n('editPasswordTitle') :
                                 this.i18n('passwordDetailsTitle');
   },
 
@@ -154,6 +152,6 @@
    * @private
    */
   getFootnote_() {
-    return this.i18n('editCompromisedPasswordFootnote', this.entry.urls.shown);
+    return this.i18n('editPasswordFootnote', this.entry.urls.shown);
   }
 });
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
index 65a13dc..c2352dc 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
@@ -186,7 +186,7 @@
    * @private
    */
   getMenuEditPasswordName_() {
-    return this.isEditDialog_ ? this.i18n('editCompromisedPassword') :
+    return this.isEditDialog_ ? this.i18n('editPassword') :
                                 this.i18n('passwordViewDetails');
   },
 
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 5da0460..0fafb9b3 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -2764,7 +2764,8 @@
 // Visits two pages from the same origin: one that runs insecure content and one
 // that doesn't.  The test checks that we propagate the insecure content state
 // from one to the other.
-IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsInsecureContentTwoTabs) {
+// TODO(crbug.com/1112300): Flaky
+IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_TestRunsInsecureContentTwoTabs) {
   ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(https_server_.Start());
 
diff --git a/chrome/browser/sync/test/integration/enable_disable_test.cc b/chrome/browser/sync/test/integration/enable_disable_test.cc
index 8c52d15..979291ba 100644
--- a/chrome/browser/sync/test/integration/enable_disable_test.cc
+++ b/chrome/browser/sync/test/integration/enable_disable_test.cc
@@ -10,6 +10,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -153,7 +154,13 @@
   DISALLOW_COPY_AND_ASSIGN(EnableDisableSingleClientTest);
 };
 
-IN_PROC_BROWSER_TEST_F(EnableDisableSingleClientTest, EnableOneAtATime) {
+// Flakiness spike on Windows, see crbug.com/1111227.
+#if defined(OS_WIN)
+#define MAYBE_EnableOneAtATime DISABLED_EnableOneAtATime
+#else
+#define MAYBE_EnableOneAtATime EnableOneAtATime
+#endif
+IN_PROC_BROWSER_TEST_F(EnableDisableSingleClientTest, MAYBE_EnableOneAtATime) {
   // Setup sync with no enabled types.
   SetupTest(/*all_types_enabled=*/false);
 
@@ -247,8 +254,14 @@
   }
 }
 
+// Flakiness spike on Windows, see crbug.com/1111227.
+#if defined(OS_WIN)
+#define MAYBE_FastDisableEnableOneAtATime DISABLED_FastDisableEnableOneAtATime
+#else
+#define MAYBE_FastDisableEnableOneAtATime FastDisableEnableOneAtATime
+#endif
 IN_PROC_BROWSER_TEST_F(EnableDisableSingleClientTest,
-                       FastDisableEnableOneAtATime) {
+                       MAYBE_FastDisableEnableOneAtATime) {
   // Setup sync with no disabled types.
   SetupTest(/*all_types_enabled=*/true);
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index 433fb827..15bb18d0 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -2799,7 +2799,8 @@
   EXPECT_FALSE(prefs->GetApp(app_id));
 }
 
-TEST_P(ArcAppLauncherForDefaultAppTest, AppIconUpdated) {
+// TODO(crbug.com/1112319): Flaky.
+TEST_P(ArcAppLauncherForDefaultAppTest, DISABLED_AppIconUpdated) {
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
   ASSERT_NE(nullptr, prefs);
 
diff --git a/chrome/browser/ui/ash/assistant/assistant_browsertest.cc b/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
index 48eb666..6605ac7d 100644
--- a/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
@@ -221,8 +221,9 @@
   ExpectBrightnessDown();
 }
 
+// TODO(crbug.com/1112278): Disabled because it's flaky.
 IN_PROC_BROWSER_TEST_F(AssistantBrowserTest,
-                       ShouldShowSingleErrorOnNetworkDown) {
+                       DISABLED_ShouldShowSingleErrorOnNetworkDown) {
   tester()->StartAssistantAndWaitForReady();
 
   ShowAssistantUi();
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
index b7e6ca5..a158b4b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
@@ -61,13 +61,17 @@
   void SetUp() override {
     BrowserWithTestWindowTest::SetUp();
 
-    profile()->CreateBookmarkModel(true);
     bookmarks::test::WaitForBookmarkModelToLoad(
         BookmarkModelFactory::GetForBrowserContext(profile()));
     controller_.reset(
         [[FakeBookmarkMenuController alloc] initWithProfile:profile()]);
   }
 
+  TestingProfile::TestingFactories GetTestingFactories() override {
+    return {{BookmarkModelFactory::GetInstance(),
+             BookmarkModelFactory::GetDefaultFactory()}};
+  }
+
   FakeBookmarkMenuController* controller() { return controller_.get(); }
 
  private:
diff --git a/chrome/browser/ui/signin_view_controller.cc b/chrome/browser/ui/signin_view_controller.cc
index 513182e..82f694d4 100644
--- a/chrome/browser/ui/signin_view_controller.cc
+++ b/chrome/browser/ui/signin_view_controller.cc
@@ -45,9 +45,6 @@
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 
-const base::Feature kOpenSignoutTab = {"OpenSignoutTab",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Returns the sign-in reason for |mode|.
 signin_metrics::Reason GetSigninReasonFromMode(profiles::BubbleViewMode mode) {
   DCHECK(SigninViewController::ShouldShowSigninForMode(mode));
@@ -380,12 +377,6 @@
 
 void SigninViewController::ShowGaiaLogoutTab(
     signin_metrics::SourceForRefreshTokenOperation source) {
-  if (!base::FeatureList::IsEnabled(kOpenSignoutTab)) {
-    IdentityManagerFactory::GetForProfile(browser_->profile())
-        ->GetAccountsMutator()
-        ->RemoveAllAccounts(source);
-    return;
-  }
 
   // Since the user may be triggering navigation from another UI element such as
   // a menu, ensure the web contents (and therefore the page that is about to be
diff --git a/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc b/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
index 20b0cc5..50726904 100644
--- a/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
+++ b/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
@@ -6,7 +6,6 @@
 #include <stddef.h>
 
 #include "base/macros.h"
-#include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
@@ -15,7 +14,6 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
-#include "content/public/test/test_navigation_observer.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 
 class AuraLinuxAccessibilityInProcessBrowserTest : public InProcessBrowserTest {
@@ -189,43 +187,3 @@
 
   VerifyEmbedRelationships();
 }
-
-// Tests that the embedded relationship is set on the main web contents when
-// the DevTools is opened.
-IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
-                       EmbeddedRelationshipWithDevTools) {
-  // Force the creation of the document's native object which sets up the
-  // relationship.
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_NE(nullptr, active_web_contents->GetRenderWidgetHostView()
-                         ->GetNativeViewAccessible());
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
-
-  // Opens DevTools docked.
-  DevToolsWindow* devtools =
-      DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true);
-  VerifyEmbedRelationships();
-
-  // Closes the DevTools window.
-  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools);
-  VerifyEmbedRelationships();
-
-  // Opens DevTools in a separate window.
-  devtools = DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), false);
-  // Waits until the DevTools is loaded.
-  base::RunLoop runloop_undocked;
-  devtools->SetLoadCompletedCallback(runloop_undocked.QuitClosure());
-  runloop_undocked.Run();
-  // Waits until the DevTools finishes the navigation.
-  views::WebView* webview = BrowserView::GetBrowserViewForBrowser(browser())
-                                ->GetDevToolsWebViewForTest();
-  content::TestNavigationObserver observer_undocked(webview->web_contents());
-  observer_undocked.WaitForNavigationFinished();
-  VerifyEmbedRelationships();
-
-  // Closes the DevTools window.
-  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools);
-  VerifyEmbedRelationships();
-}
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index adbc523..92274e8 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -568,7 +568,6 @@
       contents_container->AddChildView(std::move(devtools_web_view));
   contents_web_view_ =
       contents_container->AddChildView(std::move(contents_web_view));
-  contents_web_view_->set_is_primary_web_contents_for_window(true);
   contents_container->SetLayoutManager(std::make_unique<ContentsLayoutManager>(
       devtools_web_view_, contents_web_view_));
 
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index f015d54..116217a 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -825,16 +825,11 @@
        IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED_AND_LEAKED},
       {"showCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_SHOW},
       {"hideCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_HIDE},
-      {"editCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_EDIT},
       {"removeCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REMOVE},
       {"removeCompromisedPasswordConfirmationTitle",
        IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_TITLE},
       {"removeCompromisedPasswordConfirmationDescription",
        IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_DESCRIPTION},
-      {"editCompromisedPasswordTitle",
-       IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_TITLE},
-      {"editCompromisedPasswordFootnote",
-       IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_FOOTNOTE},
       {"editCompromisedPasswordSite",
        IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_SITE},
       {"editCompromisedPasswordApp",
@@ -911,6 +906,9 @@
       {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE},
       {"passwordDetailsTitle", IDS_SETTINGS_PASSWORDS_VIEW_DETAILS_TITLE},
       {"passwordViewDetails", IDS_SETTINGS_PASSWORD_DETAILS},
+      {"editPasswordTitle", IDS_SETTINGS_PASSWORD_EDIT_TITLE},
+      {"editPassword", IDS_SETTINGS_PASSWORD_EDIT},
+      {"editPasswordFootnote", IDS_SETTINGS_PASSWORD_EDIT_FOOTNOTE},
       {"copyPassword", IDS_SETTINGS_PASSWORD_COPY},
       {"passwordStoredOnDevice", IDS_SETTINGS_PASSWORD_STORED_ON_DEVICE},
       {"passwordStoredInAccount", IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT},
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index c100433..b5b8ea3c 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1596412401-499a1d19f67343992fe5d914f92b43fa1d307048.profdata
+chrome-mac-master-1596434376-45a7a59068fd7ea7cf40a05d52ae81f0a49abd4e.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 515440c..8cb9a3c 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1596423223-91ce8ffb27fe07737e8454516dffd91f532e6919.profdata
+chrome-win32-master-1596451854-145f78432e49c7c6a87ca8a74d340c029916cf4b.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index eb13382..22befd3e 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1596412401-579029213d4f74aa7dcc7fceb7d50be1699c065b.profdata
+chrome-win64-master-1596434376-e66572c4bd7519ea423a67f597bf938ae289c1f8.profdata
diff --git a/chrome/chrome_cleaner/os/digest_verifier.cc b/chrome/chrome_cleaner/os/digest_verifier.cc
index fecf7ad5..fc6bc378 100644
--- a/chrome/chrome_cleaner/os/digest_verifier.cc
+++ b/chrome/chrome_cleaner/os/digest_verifier.cc
@@ -82,7 +82,7 @@
   }
 
   for (const chrome_cleaner::FileDigest& digest : digests_pb.file_digests()) {
-    const base::string16 filename = base::UTF8ToWide(digest.filename());
+    const std::wstring filename = base::UTF8ToWide(digest.filename());
     digests_[base::ToLowerASCII(filename)] =
         base::ToLowerASCII(digest.digest());
   }
diff --git a/chrome/chrome_cleaner/os/disk_util.cc b/chrome/chrome_cleaner/os/disk_util.cc
index 37e615ac..5eb085d 100644
--- a/chrome/chrome_cleaner/os/disk_util.cc
+++ b/chrome/chrome_cleaner/os/disk_util.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -20,7 +21,6 @@
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -138,8 +138,8 @@
 }
 
 void AppendFileInformationField(const wchar_t* field_name,
-                                const base::string16& field,
-                                base::string16* information) {
+                                const std::wstring& field,
+                                std::wstring* information) {
   DCHECK(field_name);
   DCHECK(information);
   if (!field.empty()) {
@@ -185,7 +185,7 @@
     return true;
   }
   size_t program_path_length = program_path.value().find(L" ");
-  while (program_path_length != base::string16::npos) {
+  while (program_path_length != std::wstring::npos) {
     base::FilePath truncated_path(
         program_path.value().substr(0, program_path_length));
     if (ExpandEnvPathandWow64PathIfFileExists(truncated_path,
@@ -203,13 +203,13 @@
       exec_path.BaseName().RemoveExtension().value(), L"rundll32");
 }
 
-base::FilePath ExtractRunDllTargetPath(const base::string16& arguments) {
+base::FilePath ExtractRunDllTargetPath(const std::wstring& arguments) {
   // Some programs use rundll instead of an executable, and so their disk
   // footprint will be the first of a set of comma separated list of
   // arguments passed to rundll32.exe, which may also be "quoted", and may
   // also have command line arguments. We can't use CommandLine::GetArgs nor
   // CommandLine::GetArgumentsString() since they split/quote by spaces.
-  std::vector<base::string16> rundll_args = base::SplitString(
+  std::vector<std::wstring> rundll_args = base::SplitString(
       arguments, L",\"", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
   if (rundll_args.empty()) {
     LOG(WARNING) << "Rundll without any arguments? '" << arguments << "'";
@@ -252,7 +252,7 @@
                                 kWindowsCurrentVersionRegKeyName,
                                 KEY_READ | KEY_WOW64_64KEY);
   DCHECK(version_key.Valid());
-  base::string16 program_files_path;
+  std::wstring program_files_path;
   LONG error =
       version_key.ReadValue(kProgramFilesDirValueName, &program_files_path);
   if (error != ERROR_SUCCESS) {
@@ -268,7 +268,7 @@
                                 kWindowsCurrentVersionRegKeyName,
                                 KEY_READ | KEY_WOW64_32KEY);
   DCHECK(version_key.Valid());
-  base::string16 program_files_path;
+  std::wstring program_files_path;
   LONG error =
       version_key.ReadValue(kProgramFilesDirValueName, &program_files_path);
   if (error != ERROR_SUCCESS) {
@@ -279,13 +279,13 @@
   return base::FilePath(program_files_path).Append(input_path);
 }
 
-bool NameContainsWildcards(const base::string16& name) {
+bool NameContainsWildcards(const std::wstring& name) {
   return (name.find(L"*") != base::FilePath::StringType::npos ||
           name.find(L"?") != base::FilePath::StringType::npos);
 }
 
-bool NameMatchesPattern(const base::string16& name,
-                        const base::string16& pattern,
+bool NameMatchesPattern(const std::wstring& name,
+                        const std::wstring& pattern,
                         const wchar_t escape_char) {
   return String16WildcardMatchInsensitive(name, pattern, escape_char);
 }
@@ -310,7 +310,7 @@
 }
 
 bool PathHasActiveExtension(const base::FilePath& file_path) {
-  base::string16 extension;
+  std::wstring extension;
   if (base::EndsWith(file_path.value(), kDefaultDataStream,
                      base::CompareCase::INSENSITIVE_ASCII)) {
     // Default stream with an explicit stream type specified.
@@ -319,7 +319,7 @@
     // check.
     size_t true_path_len =
         file_path.value().size() - wcslen(kDefaultDataStream);
-    base::string16 true_path = file_path.value().substr(0, true_path_len);
+    std::wstring true_path = file_path.value().substr(0, true_path_len);
     extension = base::FilePath(true_path).Extension();
   } else {
     CHECK_EQ(base::FilePath::StringType::npos,
@@ -397,14 +397,14 @@
   }
 }
 
-base::string16 FileInformationToString(
+std::wstring FileInformationToString(
     const internal::FileInformation& file_information) {
   if (file_information.path.empty())
     return L"";
 
   // We add the first field directly without using any AppendFileInformation*()
   // function since the first field should not be prepended with a separator.
-  base::string16 content = L"path = '" + file_information.path + L"'";
+  std::wstring content = L"path = '" + file_information.path + L"'";
 
   AppendFileInformationField(L"file_creation_date",
                              base::UTF8ToWide(file_information.creation_date),
@@ -439,7 +439,7 @@
   return content;
 }
 
-bool IsCompanyOnIgnoredReportingList(const base::string16& company_name) {
+bool IsCompanyOnIgnoredReportingList(const std::wstring& company_name) {
   return base::Contains(kCompanyIgnoredReportingList, company_name);
 }
 
@@ -700,8 +700,8 @@
 }
 
 bool PathEqual(const base::FilePath& path1, const base::FilePath& path2) {
-  base::string16 long_path1;
-  base::string16 long_path2;
+  std::wstring long_path1;
+  std::wstring long_path2;
   ConvertToLongPath(path1.value(), &long_path1);
   ConvertToLongPath(path2.value(), &long_path2);
   return base::FilePath::CompareEqualIgnoreCase(long_path1, long_path2);
@@ -709,8 +709,8 @@
 
 bool FilePathLess::operator()(const base::FilePath& smaller,
                               const base::FilePath& larger) const {
-  base::string16 long_smaller;
-  base::string16 long_larger;
+  std::wstring long_smaller;
+  std::wstring long_larger;
   ConvertToLongPath(smaller.value(), &long_smaller);
   ConvertToLongPath(larger.value(), &long_larger);
   return base::FilePath::CompareLessIgnoreCase(long_smaller, long_larger);
@@ -813,7 +813,7 @@
 
 bool OverwriteZoneIdentifier(const base::FilePath& path) {
   const DWORD kShare = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
-  base::string16 stream_path = path.value() + L":Zone.Identifier";
+  std::wstring stream_path = path.value() + L":Zone.Identifier";
   HANDLE file = CreateFile(stream_path.c_str(), GENERIC_WRITE, kShare, nullptr,
                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
   if (INVALID_HANDLE_VALUE == file)
@@ -837,7 +837,7 @@
 }
 
 base::FilePath ExtractExecutablePathFromRegistryContent(
-    const base::string16& content) {
+    const std::wstring& content) {
   // The content of the registry key can be a fullpath to an executable as is.
   base::FilePath program_path(content);
   base::FilePath return_program_path;
diff --git a/chrome/chrome_cleaner/os/disk_util.h b/chrome/chrome_cleaner/os/disk_util.h
index 70a31af..43147b48 100644
--- a/chrome/chrome_cleaner/os/disk_util.h
+++ b/chrome/chrome_cleaner/os/disk_util.h
@@ -16,7 +16,6 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/strings/string16.h"
 #include "base/win/scoped_handle.h"
 #include "chrome/chrome_cleaner/os/disk_util_types.h"
 #include "chrome/chrome_cleaner/os/file_path_set.h"
@@ -77,12 +76,12 @@
 void ExpandWow64Path(const base::FilePath& path, base::FilePath* expanded_path);
 
 // Return a string16 representation of |file_information|.
-base::string16 FileInformationToString(
+std::wstring FileInformationToString(
     const internal::FileInformation& file_information);
 
 // Returns true if the given |company_name| is on the list of companies whose
 // executables' details should not be reported.
-bool IsCompanyOnIgnoredReportingList(const base::string16& company_name);
+bool IsCompanyOnIgnoredReportingList(const std::wstring& company_name);
 
 // Returns true if the given |path| refers to an executable whose details
 // should not be reported.
@@ -170,17 +169,17 @@
 // Return a file path found in the content text, typically from a registry entry
 // that may have arguments, or be the argument of a rundll.
 base::FilePath ExtractExecutablePathFromRegistryContent(
-    const base::string16& content);
+    const std::wstring& content);
 
 // Perform environment variable expansion and wow64 path replacement.
 base::FilePath ExpandEnvPathAndWow64Path(const base::FilePath& path);
 
 // Return true if |name| contains wildcard characters '?' or '*'.
-bool NameContainsWildcards(const base::string16& name);
+bool NameContainsWildcards(const std::wstring& name);
 
 // See |String16WildcardMatchInsensitive|.
-bool NameMatchesPattern(const base::string16& name,
-                        const base::string16& pattern,
+bool NameMatchesPattern(const std::wstring& name,
+                        const std::wstring& pattern,
                         const wchar_t escape_char);
 
 // Retrieves basic path information for |expanded_path|.
diff --git a/chrome/chrome_cleaner/os/disk_util_types.cc b/chrome/chrome_cleaner/os/disk_util_types.cc
index fd86623..03dc933 100644
--- a/chrome/chrome_cleaner/os/disk_util_types.cc
+++ b/chrome/chrome_cleaner/os/disk_util_types.cc
@@ -10,19 +10,19 @@
 
 FileInformation::FileInformation() = default;
 
-FileInformation::FileInformation(const base::string16& path,
+FileInformation::FileInformation(const std::wstring& path,
                                  const std::string& creation_date,
                                  const std::string& last_modified_date,
                                  const std::string& sha256,
                                  int64_t size,
-                                 const base::string16& company_name,
-                                 const base::string16& company_short_name,
-                                 const base::string16& product_name,
-                                 const base::string16& product_short_name,
-                                 const base::string16& internal_name,
-                                 const base::string16& original_filename,
-                                 const base::string16& file_description,
-                                 const base::string16& file_version,
+                                 const std::wstring& company_name,
+                                 const std::wstring& company_short_name,
+                                 const std::wstring& product_name,
+                                 const std::wstring& product_short_name,
+                                 const std::wstring& internal_name,
+                                 const std::wstring& original_filename,
+                                 const std::wstring& file_description,
+                                 const std::wstring& file_version,
                                  bool active_file)
     : path(path),
       creation_date(creation_date),
diff --git a/chrome/chrome_cleaner/os/disk_util_types.h b/chrome/chrome_cleaner/os/disk_util_types.h
index 6de2f11..6e71244 100644
--- a/chrome/chrome_cleaner/os/disk_util_types.h
+++ b/chrome/chrome_cleaner/os/disk_util_types.h
@@ -7,8 +7,6 @@
 
 #include <string>
 
-#include "base/strings/string16.h"
-
 namespace chrome_cleaner {
 
 namespace internal {
@@ -24,19 +22,19 @@
 struct FileInformation {
   FileInformation();
 
-  FileInformation(const base::string16& path,
+  FileInformation(const std::wstring& path,
                   const std::string& creation_date,
                   const std::string& last_modified_date,
                   const std::string& sha256,
                   int64_t size,
-                  const base::string16& company_name,
-                  const base::string16& company_short_name,
-                  const base::string16& product_name,
-                  const base::string16& product_short_name,
-                  const base::string16& internal_name,
-                  const base::string16& original_filename,
-                  const base::string16& file_description,
-                  const base::string16& file_version,
+                  const std::wstring& company_name,
+                  const std::wstring& company_short_name,
+                  const std::wstring& product_name,
+                  const std::wstring& product_short_name,
+                  const std::wstring& internal_name,
+                  const std::wstring& original_filename,
+                  const std::wstring& file_description,
+                  const std::wstring& file_version,
                   bool active_file = false);
 
   FileInformation(const FileInformation& other);
@@ -45,20 +43,20 @@
 
   FileInformation& operator=(const FileInformation& other);
 
-  base::string16 path;
+  std::wstring path;
   std::string creation_date;
   std::string last_modified_date;
   std::string sha256;
   int64_t size = 0ULL;
   // The following are internal fields of the PE header.
-  base::string16 company_name;
-  base::string16 company_short_name;
-  base::string16 product_name;
-  base::string16 product_short_name;
-  base::string16 internal_name;
-  base::string16 original_filename;
-  base::string16 file_description;
-  base::string16 file_version;
+  std::wstring company_name;
+  std::wstring company_short_name;
+  std::wstring product_name;
+  std::wstring product_short_name;
+  std::wstring internal_name;
+  std::wstring original_filename;
+  std::wstring file_description;
+  std::wstring file_version;
   bool active_file = false;
 };
 
diff --git a/chrome/chrome_cleaner/os/disk_util_unittest.cc b/chrome/chrome_cleaner/os/disk_util_unittest.cc
index f930261..bbc6898 100644
--- a/chrome/chrome_cleaner/os/disk_util_unittest.cc
+++ b/chrome/chrome_cleaner/os/disk_util_unittest.cc
@@ -133,10 +133,10 @@
 }
 
 bool DoesVolumeSupportNamedStreams(const base::FilePath& path) {
-  std::vector<base::string16> components;
+  std::vector<std::wstring> components;
   path.GetComponents(&components);
   DCHECK(!components.empty());
-  base::string16& drive = components[0];
+  std::wstring& drive = components[0];
   drive += L'\\';
   DWORD system_flags = 0;
   if (::GetVolumeInformation(drive.c_str(), nullptr, 0, nullptr, nullptr,
@@ -174,10 +174,10 @@
 // and passes the result to ExtractExecutablePathFromRegistryContent to get a
 // file path. Returns success if every file path matches |expected_path|.
 ::testing::AssertionResult ExtractExecutablePathFromMockRegistryAndExpect(
-    const base::string16& registry_path,
+    const std::wstring& registry_path,
     const base::FilePath& expected_path) {
-  for (const base::string16& registry_content : kMockRegistryContents) {
-    base::string16 full_registry_content =
+  for (const std::wstring& registry_content : kMockRegistryContents) {
+    std::wstring full_registry_content =
         base::StringPrintf(registry_content.c_str(), registry_path.c_str());
     base::FilePath extracted_path =
         ExtractExecutablePathFromRegistryContent(full_registry_content);
@@ -832,7 +832,7 @@
   // DLL's that would have to be copied into the folder too.
   base::FilePath source_exe_path(
       executable_path.Append(kTestProcessExecutableName));
-  base::string16 target_exe_name = base::StrCat(
+  std::wstring target_exe_name = base::StrCat(
       {base::UTF8ToWide(base::UnguessableToken::Create().ToString()), L".exe"});
   base::FilePath target_exe_path(executable_path.Append(target_exe_name));
 
@@ -888,7 +888,7 @@
 TEST(DiskUtilTests, ExtractExecutablePathFromRegistryContentWithEnvVariable) {
   // This test expects files to be placed in %TEMP% and not anywhere else
   // ScopedTempDir might decide to put them.
-  base::string16 temp_str;
+  std::wstring temp_str;
   ASSERT_NE(0U, ::GetEnvironmentVariableW(
                     L"TEMP", ::base::WriteInto(&temp_str, MAX_PATH), MAX_PATH))
       << logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
@@ -972,7 +972,7 @@
 
   EXPECT_FALSE(whitelisted);
 
-  base::string16 sanitized_path = SanitizePath(temp_file);
+  std::wstring sanitized_path = SanitizePath(temp_file);
 
   EXPECT_EQ(sanitized_path, file_information.path);
   EXPECT_FALSE(file_information.creation_date.empty());
@@ -1107,7 +1107,7 @@
 }
 
 TEST(DiskUtilTests, FileInformationToString) {
-  base::string16 display_str = FileInformationToString(kFileInformation1);
+  std::wstring display_str = FileInformationToString(kFileInformation1);
   EXPECT_EQ(kFileInformation1ExpectedString, display_str);
 }
 
diff --git a/chrome/chrome_cleaner/os/file_path_sanitization.cc b/chrome/chrome_cleaner/os/file_path_sanitization.cc
index 16d44316..a70a76e 100644
--- a/chrome/chrome_cleaner/os/file_path_sanitization.cc
+++ b/chrome/chrome_cleaner/os/file_path_sanitization.cc
@@ -208,8 +208,8 @@
   return paths;
 }
 
-std::map<int, base::string16> PathKeyToSanitizeString() {
-  std::map<int, base::string16> path_key_to_sanitize_string;
+std::map<int, std::wstring> PathKeyToSanitizeString() {
+  std::map<int, std::wstring> path_key_to_sanitize_string;
   for (const auto* rule = sanitization_internal::rewrite_rules;
        rule->path != nullptr; ++rule) {
     path_key_to_sanitize_string.insert(std::make_pair(rule->id, rule->path));
@@ -222,12 +222,12 @@
 }
 
 base::FilePath NormalizePath(const base::FilePath& path) {
-  base::string16 long_path;
+  std::wstring long_path;
   ConvertToLongPath(path.value(), &long_path);
   return base::FilePath(base::ToLowerASCII(long_path));
 }
 
-void ConvertToLongPath(const base::string16& path, base::string16* long_path) {
+void ConvertToLongPath(const std::wstring& path, std::wstring* long_path) {
   DCHECK(long_path);
   DWORD long_path_len = ::GetLongPathName(path.c_str(), nullptr, 0);
   if (long_path_len > 0UL) {
@@ -239,11 +239,11 @@
   }
 }
 
-base::string16 SanitizePath(const base::FilePath& path) {
+std::wstring SanitizePath(const base::FilePath& path) {
   return SanitizePathImpl(path).value();
 }
 
-base::string16 SanitizeCommandLine(const base::CommandLine& command_line) {
+std::wstring SanitizeCommandLine(const base::CommandLine& command_line) {
   base::FilePath sanitized_program =
       SanitizePathImpl(command_line.GetProgram());
   base::CommandLine sanitized_command_line(sanitized_program);
diff --git a/chrome/chrome_cleaner/os/file_path_sanitization.h b/chrome/chrome_cleaner/os/file_path_sanitization.h
index ccdfa771..2b503809 100644
--- a/chrome/chrome_cleaner/os/file_path_sanitization.h
+++ b/chrome/chrome_cleaner/os/file_path_sanitization.h
@@ -8,11 +8,11 @@
 #include <windows.h>
 
 #include <map>
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/strings/string16.h"
 
 namespace chrome_cleaner {
 
@@ -42,13 +42,13 @@
 std::vector<base::FilePath> GetRewrittenPaths();
 
 // Returns the map of key paths to the corresponding sanitization string.
-std::map<int, base::string16> PathKeyToSanitizeString();
+std::map<int, std::wstring> PathKeyToSanitizeString();
 
 // Convert a CSIDL to a key that can be used with PathService::Get().
 int CsidlToPathServiceKey(int CSIDL);
 
 // Return the long path equivalent of |path| in |long_path|.
-void ConvertToLongPath(const base::string16& path, base::string16* long_path);
+void ConvertToLongPath(const std::wstring& path, std::wstring* long_path);
 
 // Converts a FilePath to a common format to prevent comparison errors because
 // of case sensitivity or short vs. long path formats.
@@ -57,10 +57,10 @@
 // Return the value of the |path| after being sanitized. A path is sanitized by
 // replacing the portion that represents a CSIDL. Must never be called before
 // InitializeFilePathSanitization().
-base::string16 SanitizePath(const base::FilePath& path);
+std::wstring SanitizePath(const base::FilePath& path);
 
 // Return the command line string after the executable path is sanitized.
-base::string16 SanitizeCommandLine(const base::CommandLine& command_line);
+std::wstring SanitizeCommandLine(const base::CommandLine& command_line);
 
 // If |input_path| is a relative path, |csidl| is used as one of the CSIDL_*
 // #defines in shlobj.h to identify the root path, to which |input_path is
diff --git a/chrome/chrome_cleaner/os/file_path_sanitization_unittest.cc b/chrome/chrome_cleaner/os/file_path_sanitization_unittest.cc
index c1de035..88eefab 100644
--- a/chrome/chrome_cleaner/os/file_path_sanitization_unittest.cc
+++ b/chrome/chrome_cleaner/os/file_path_sanitization_unittest.cc
@@ -14,7 +14,7 @@
 
 namespace {
 
-base::string16 FirstComponent(const base::string16& original) {
+std::wstring FirstComponent(const std::wstring& original) {
   return original.substr(0, original.find(L"\\"));
 }
 
@@ -51,11 +51,11 @@
                                      &programfiles_folder));
 
   base::FilePath absolute(L"C:\\Dummy\\Dummy.exe");
-  base::string16 result = SanitizePath(absolute);
+  std::wstring result = SanitizePath(absolute);
   EXPECT_EQ(NormalizePath(absolute).value(), result);
 
   base::FilePath relative(programfiles_folder.Append(L"Dummy\\Dummy.exe"));
-  base::string16 sanitized_relative = SanitizePath(relative);
+  std::wstring sanitized_relative = SanitizePath(relative);
   EXPECT_NE(sanitized_relative, relative.value());
   EXPECT_EQ(L"CSIDL_PROGRAM_FILES\\dummy\\dummy.exe", sanitized_relative);
 
@@ -103,7 +103,7 @@
 
   base::CommandLine already_sanitized(switches);
   already_sanitized.SetProgram(base::FilePath(L"c:\\dummy\\dummy.exe"));
-  base::string16 result = SanitizeCommandLine(already_sanitized);
+  std::wstring result = SanitizeCommandLine(already_sanitized);
   EXPECT_EQ(already_sanitized.GetCommandLineString(), result);
 
   base::FilePath programfiles_folder;
@@ -114,10 +114,9 @@
 
   base::CommandLine to_sanitize(switches);
   to_sanitize.SetProgram(exe_in_programfiles);
-  base::string16 sanitized_cmd = SanitizeCommandLine(to_sanitize);
+  std::wstring sanitized_cmd = SanitizeCommandLine(to_sanitize);
   EXPECT_NE(to_sanitize.GetCommandLineString(), sanitized_cmd);
-  EXPECT_EQ(sanitized_cmd.find(exe_in_programfiles.value()),
-            base::string16::npos)
+  EXPECT_EQ(sanitized_cmd.find(exe_in_programfiles.value()), std::wstring::npos)
       << sanitized_cmd;
 
   switches.AppendSwitchPath("path", exe_in_programfiles);
@@ -125,8 +124,7 @@
   to_sanitize = base::CommandLine(switches);
   sanitized_cmd = SanitizeCommandLine(to_sanitize);
   EXPECT_NE(to_sanitize.GetCommandLineString(), sanitized_cmd);
-  EXPECT_EQ(sanitized_cmd.find(exe_in_programfiles.value()),
-            base::string16::npos)
+  EXPECT_EQ(sanitized_cmd.find(exe_in_programfiles.value()), std::wstring::npos)
       << sanitized_cmd;
 }
 
diff --git a/chrome/chrome_cleaner/os/file_path_set.cc b/chrome/chrome_cleaner/os/file_path_set.cc
index b7ca24d..ab9c9f2 100644
--- a/chrome/chrome_cleaner/os/file_path_set.cc
+++ b/chrome/chrome_cleaner/os/file_path_set.cc
@@ -5,8 +5,8 @@
 #include "chrome/chrome_cleaner/os/file_path_set.h"
 
 #include <algorithm>
+#include <string>
 
-#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "chrome/chrome_cleaner/os/disk_util.h"
 #include "chrome/chrome_cleaner/os/file_path_sanitization.h"
diff --git a/chrome/chrome_cleaner/os/file_removal_status_updater.cc b/chrome/chrome_cleaner/os/file_removal_status_updater.cc
index 56544af4..7d5376a 100644
--- a/chrome/chrome_cleaner/os/file_removal_status_updater.cc
+++ b/chrome/chrome_cleaner/os/file_removal_status_updater.cc
@@ -200,7 +200,7 @@
       << "Unknown RemovalStatus: need to update "
          "RemovalStatusCanBeOverriddenBy()?";
 
-  const base::string16 sanitized_path = SanitizePath(path);
+  const std::wstring sanitized_path = SanitizePath(path);
 
   base::AutoLock lock(removal_status_lock_);
 
@@ -228,7 +228,7 @@
 }
 
 RemovalStatus FileRemovalStatusUpdater::GetRemovalStatusOfSanitizedPath(
-    const base::string16& sanitized_path) const {
+    const std::wstring& sanitized_path) const {
   base::AutoLock lock(removal_status_lock_);
   const auto it = removal_statuses_.find(sanitized_path);
   return it == removal_statuses_.end() ? REMOVAL_STATUS_UNSPECIFIED
@@ -242,7 +242,7 @@
   DCHECK(status > QUARANTINE_STATUS_UNSPECIFIED &&
          status <= QuarantineStatus_MAX);
 
-  const base::string16 sanitized_path = SanitizePath(path);
+  const std::wstring sanitized_path = SanitizePath(path);
 
   base::AutoLock lock(removal_status_lock_);
 
@@ -264,7 +264,7 @@
 
 QuarantineStatus FileRemovalStatusUpdater::GetQuarantineStatus(
     const base::FilePath& path) const {
-  const base::string16 sanitized_path = SanitizePath(path);
+  const std::wstring sanitized_path = SanitizePath(path);
 
   base::AutoLock lock(removal_status_lock_);
 
diff --git a/chrome/chrome_cleaner/os/file_removal_status_updater.h b/chrome/chrome_cleaner/os/file_removal_status_updater.h
index 5e0ae0f..89b79a3 100644
--- a/chrome/chrome_cleaner/os/file_removal_status_updater.h
+++ b/chrome/chrome_cleaner/os/file_removal_status_updater.h
@@ -69,7 +69,7 @@
     QuarantineStatus quarantine_status = QUARANTINE_STATUS_UNSPECIFIED;
   };
 
-  typedef std::unordered_map<base::string16, FileRemovalStatus>
+  typedef std::unordered_map<std::wstring, FileRemovalStatus>
       SanitizedPathToRemovalStatusMap;
 
   static FileRemovalStatusUpdater* GetInstance();
@@ -92,7 +92,7 @@
   // REMOVAL_STATUS_UNSPECIFIED if the removal status have never
   // been updated for an unsanitized form of that path.
   RemovalStatus GetRemovalStatusOfSanitizedPath(
-      const base::string16& sanitized_path) const;
+      const std::wstring& sanitized_path) const;
 
   // Updates quarantine status for a file given by |path|.
   // Note: UpdateRemovalStatus should be called for |path| at some point as
diff --git a/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc b/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc
index 21e5400..44cf158 100644
--- a/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc
+++ b/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc
@@ -58,8 +58,8 @@
 TEST_F(FileRemovalStatusUpdaterTest, UpdateRemovalStatus) {
   // This function uses GetRemovalStatusOfSanitizedPath to cut down on the
   // number of times it calls SanitizePath on the same paths, which is slow.
-  const base::string16 file_1_sanitized = SanitizePath(file_1_);
-  const base::string16 file_2_sanitized = SanitizePath(file_2_);
+  const std::wstring file_1_sanitized = SanitizePath(file_1_);
+  const std::wstring file_2_sanitized = SanitizePath(file_2_);
 
   // Creates a vector of all RemovalStatus enum values to improve readability
   // of loops in this test and ensure that all RemovalStatus enumerators are
@@ -117,7 +117,7 @@
           instance_->GetAllRemovalStatuses();
       EXPECT_EQ(2U, all_statuses.size());
       for (const auto& path_and_status : all_statuses) {
-        base::string16 sanitized_path = path_and_status.first;
+        std::wstring sanitized_path = path_and_status.first;
         FileRemovalStatusUpdater::FileRemovalStatus status =
             path_and_status.second;
         EXPECT_EQ(instance_->GetRemovalStatusOfSanitizedPath(sanitized_path),
@@ -193,12 +193,12 @@
 
   // Path should be accessible with any capitalization, sanitized or
   // unsanitized.
-  base::string16 lowercase_path = base::ToLowerASCII(path.value());
+  std::wstring lowercase_path = base::ToLowerASCII(path.value());
   EXPECT_EQ(REMOVAL_STATUS_REMOVED, instance_->GetRemovalStatus(path));
   EXPECT_EQ(REMOVAL_STATUS_REMOVED,
             instance_->GetRemovalStatus(base::FilePath(lowercase_path)));
 
-  base::string16 sanitized_path = SanitizePath(path);
+  std::wstring sanitized_path = SanitizePath(path);
   EXPECT_EQ(REMOVAL_STATUS_REMOVED,
             instance_->GetRemovalStatusOfSanitizedPath(sanitized_path));
 
diff --git a/chrome/chrome_cleaner/os/file_remover.cc b/chrome/chrome_cleaner/os/file_remover.cc
index f4d71b30..1236448 100644
--- a/chrome/chrome_cleaner/os/file_remover.cc
+++ b/chrome/chrome_cleaner/os/file_remover.cc
@@ -62,15 +62,15 @@
   if (path.empty())
     return false;
 
-  const base::string16& path_str = path.value();
+  const std::wstring& path_str = path.value();
   // Disallow anything with "\..\".
-  if (path_str.find(L"\\..\\") != base::string16::npos)
+  if (path_str.find(L"\\..\\") != std::wstring::npos)
     return false;
 
   // Ensure the path does not specify a drive root: require a character other
   // than \/:. after the last :
   size_t last_colon_pos = path_str.rfind(L':');
-  if (last_colon_pos == base::string16::npos)
+  if (last_colon_pos == std::wstring::npos)
     return true;
   for (size_t index = last_colon_pos + 1; index < path_str.size(); ++index) {
     wchar_t character = path_str[index];
diff --git a/chrome/chrome_cleaner/os/file_remover.h b/chrome/chrome_cleaner/os/file_remover.h
index b3d85d37..3e93c3d 100644
--- a/chrome/chrome_cleaner/os/file_remover.h
+++ b/chrome/chrome_cleaner/os/file_remover.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/strings/string16.h"
 #include "chrome/chrome_cleaner/logging/proto/removal_status.pb.h"
 #include "chrome/chrome_cleaner/os/digest_verifier.h"
 #include "chrome/chrome_cleaner/os/file_path_set.h"
diff --git a/chrome/chrome_cleaner/os/post_reboot_registration.cc b/chrome/chrome_cleaner/os/post_reboot_registration.cc
index 5499cbb..468ff06 100644
--- a/chrome/chrome_cleaner/os/post_reboot_registration.cc
+++ b/chrome/chrome_cleaner/os/post_reboot_registration.cc
@@ -6,9 +6,10 @@
 
 #include <windows.h>
 
+#include <string>
+
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
 #include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
@@ -28,7 +29,7 @@
 }  // namespace
 
 PostRebootRegistration::PostRebootRegistration(
-    const base::string16& product_shortname)
+    const std::wstring& product_shortname)
     : product_shortname_(product_shortname) {}
 
 bool PostRebootRegistration::RegisterRunOnceOnRestart(
@@ -45,7 +46,7 @@
 
   base::win::RegKey run_once_key(HKEY_CURRENT_USER, kRunOnceKeyPath, KEY_WRITE);
   DCHECK(run_once_key.Valid());
-  base::string16 run_once_value(command_line.GetCommandLineString());
+  std::wstring run_once_value(command_line.GetCommandLineString());
   if (run_once_value.length() > 260) {
     LOG(ERROR) << "RunOnce value is too long: " << run_once_value.length()
                << " characters.";
@@ -55,7 +56,7 @@
   base::win::RegKey switches_key(HKEY_CURRENT_USER,
                                  GetPostRebootSwitchKeyPath().c_str(),
                                  KEY_SET_VALUE | KEY_WOW64_32KEY);
-  base::string16 switches_value(switches.GetCommandLineString());
+  std::wstring switches_value(switches.GetCommandLineString());
   if (switches_key.WriteValue(base::UTF8ToWide(cleanup_id).c_str(),
                               switches_value.c_str()) != ERROR_SUCCESS) {
     PLOG(ERROR) << "Failed to Write RunOnce value with: "
@@ -94,8 +95,8 @@
   }
 }
 
-base::string16 PostRebootRegistration::RunOnceOnRestartRegisteredValue() {
-  base::string16 reg_value;
+std::wstring PostRebootRegistration::RunOnceOnRestartRegisteredValue() {
+  std::wstring reg_value;
   base::win::RegKey run_once_key(HKEY_CURRENT_USER, kRunOnceKeyPath, KEY_READ);
   if (run_once_key.Valid()) {
     // There is no need to check the return value, since ReadValue will leave
@@ -112,7 +113,7 @@
                                  GetPostRebootSwitchKeyPath().c_str(),
                                  KEY_QUERY_VALUE | KEY_WOW64_32KEY);
 
-  base::string16 string_value;
+  std::wstring string_value;
   if (switches_key.ReadValue(base::UTF8ToWide(cleanup_id).c_str(),
                              &string_value) != ERROR_SUCCESS) {
     PLOG(ERROR) << "Failed to Read RunOnce reboot switches.";
@@ -130,8 +131,8 @@
 }
 
 // static
-base::string16 PostRebootRegistration::GetPostRebootSwitchKeyPath() {
-  base::string16 path(chrome_cleaner::kSoftwareRemovalToolRegistryKey);
+std::wstring PostRebootRegistration::GetPostRebootSwitchKeyPath() {
+  std::wstring path(chrome_cleaner::kSoftwareRemovalToolRegistryKey);
   path += L"\\";
   path += chrome_cleaner::kCleanerSubKey;
   path += L"\\";
diff --git a/chrome/chrome_cleaner/os/post_reboot_registration.h b/chrome/chrome_cleaner/os/post_reboot_registration.h
index fcdd4db..6412b64 100644
--- a/chrome/chrome_cleaner/os/post_reboot_registration.h
+++ b/chrome/chrome_cleaner/os/post_reboot_registration.h
@@ -9,14 +9,13 @@
 #include <string>
 
 #include "base/command_line.h"
-#include "base/strings/string16.h"
 
 namespace chrome_cleaner {
 
 // Registers the application to execute again after a reboot.
 class PostRebootRegistration {
  public:
-  explicit PostRebootRegistration(const base::string16& product_shortname);
+  explicit PostRebootRegistration(const std::wstring& product_shortname);
 
   // Register the current running app to be called post reboot with the provided
   // command line switches. Returns false if failed.
@@ -29,7 +28,7 @@
 
   // Returns the value stored by |RegisterRunOnceOnRestart|, or an empty string
   // if there is none.
-  base::string16 RunOnceOnRestartRegisteredValue();
+  std::wstring RunOnceOnRestartRegisteredValue();
 
   // Fills |out_command_line| with the switches of the post-reboot run by
   // reading from a cleanup-id dependent registry key. The registry key is then
@@ -44,9 +43,9 @@
 
   // Returns the registry key path in which the full post-reboot command line
   // switches can be found.
-  static base::string16 GetPostRebootSwitchKeyPath();
+  static std::wstring GetPostRebootSwitchKeyPath();
 
-  base::string16 product_shortname_;
+  std::wstring product_shortname_;
 };
 
 }  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/os/process.cc b/chrome/chrome_cleaner/os/process.cc
index 5aad5ca..7a71234 100644
--- a/chrome/chrome_cleaner/os/process.cc
+++ b/chrome/chrome_cleaner/os/process.cc
@@ -15,7 +15,7 @@
 namespace chrome_cleaner {
 
 bool GetLoadedModuleFileNames(HANDLE process,
-                              std::set<base::string16>* module_names) {
+                              std::set<std::wstring>* module_names) {
   std::vector<HMODULE> module_handles;
   size_t modules_count = 128;
   // Adjust array size for all modules to fit into it.
@@ -44,12 +44,12 @@
       PLOG(ERROR) << "Failed to get module filename";
       continue;
     }
-    module_names->insert(base::string16(module_name, module_name_length));
+    module_names->insert(std::wstring(module_name, module_name_length));
   }
   return true;
 }
 
-bool GetProcessExecutablePath(HANDLE process, base::string16* path) {
+bool GetProcessExecutablePath(HANDLE process, std::wstring* path) {
   DCHECK(path);
 
   std::vector<wchar_t> image_path(MAX_PATH);
diff --git a/chrome/chrome_cleaner/os/process.h b/chrome/chrome_cleaner/os/process.h
index 813d97cd..0bd087f 100644
--- a/chrome/chrome_cleaner/os/process.h
+++ b/chrome/chrome_cleaner/os/process.h
@@ -8,9 +8,9 @@
 #include <windows.h>
 
 #include <set>
+#include <string>
 
 #include "base/process/process_metrics_iocounters.h"
-#include "base/strings/string16.h"
 
 namespace chrome_cleaner {
 
@@ -31,12 +31,12 @@
 // The function might not work when enumerating modules of x64 process from a
 // x86 process.
 bool GetLoadedModuleFileNames(HANDLE process,
-                              std::set<base::string16>* module_names);
+                              std::set<std::wstring>* module_names);
 
 // Retrieve process executable module in win32 path format.
 // Provided handle must have PROCESS_QUERY_LIMITED_INFORMATION or
 // PROCESS_QUERY_INFORMATION access right.
-bool GetProcessExecutablePath(HANDLE process, base::string16* path);
+bool GetProcessExecutablePath(HANDLE process, std::wstring* path);
 
 // Retrieves system resource usage stats for the given process.
 // Provided handle must have PROCESS_QUERY_LIMITED_INFORMATION or
diff --git a/chrome/chrome_cleaner/os/process_unittest.cc b/chrome/chrome_cleaner/os/process_unittest.cc
index 2ce9acd..407ad111 100644
--- a/chrome/chrome_cleaner/os/process_unittest.cc
+++ b/chrome/chrome_cleaner/os/process_unittest.cc
@@ -22,10 +22,10 @@
 namespace {
 
 bool PathIsInSet(const base::FilePath& path,
-                 const std::set<base::string16>& path_set) {
-  const base::string16 lower_case_path = base::ToLowerASCII(path.value());
+                 const std::set<std::wstring>& path_set) {
+  const std::wstring lower_case_path = base::ToLowerASCII(path.value());
   return std::find_if(path_set.begin(), path_set.end(),
-                      [&lower_case_path](const base::string16& name) {
+                      [&lower_case_path](const std::wstring& name) {
                         return lower_case_path == base::ToLowerASCII(name);
                       }) != path_set.end();
 }
@@ -33,7 +33,7 @@
 }  // namespace
 
 TEST(ProcessTest, LoadedModules_Self) {
-  std::set<base::string16> names;
+  std::set<std::wstring> names;
   ASSERT_TRUE(
       GetLoadedModuleFileNames(base::GetCurrentProcessHandle(), &names));
 
@@ -44,7 +44,7 @@
 }
 
 TEST(ProcessTest, LoadedModules_InvalidProcess) {
-  std::set<base::string16> names;
+  std::set<std::wstring> names;
   // INVALID_HANDLE_VALUE is actually -1, the same as the pseudo-handle that
   // represents the current process, so in this context it's not invalid. Test
   // null instead. Windows, everyone!
@@ -52,7 +52,7 @@
 }
 
 TEST(ProcessTest, ProcessExecutablePath_Self) {
-  base::string16 path;
+  std::wstring path;
   ASSERT_TRUE(GetProcessExecutablePath(base::GetCurrentProcessHandle(), &path));
 
   const base::FilePath self_exe_path =
@@ -62,7 +62,7 @@
 }
 
 TEST(ProcessTest, ProcessExecutablePath_InvalidProcess) {
-  base::string16 path;
+  std::wstring path;
   EXPECT_FALSE(GetProcessExecutablePath(nullptr, &path));
 }
 
diff --git a/chrome/chrome_cleaner/os/rebooter.cc b/chrome/chrome_cleaner/os/rebooter.cc
index 9e73d61..3f902f4c 100644
--- a/chrome/chrome_cleaner/os/rebooter.cc
+++ b/chrome/chrome_cleaner/os/rebooter.cc
@@ -32,7 +32,7 @@
 };
 
 // The name of the task to run post reboot.
-base::string16 PostRebootRunTaskName(const base::string16& product_shortname) {
+std::wstring PostRebootRunTaskName(const std::wstring& product_shortname) {
   return product_shortname + L" post reboot run";
 }
 
@@ -43,7 +43,7 @@
   return base::CommandLine::ForCurrentProcess()->HasSwitch(kPostRebootSwitch);
 }
 
-Rebooter::Rebooter(const base::string16& product_shortname)
+Rebooter::Rebooter(const std::wstring& product_shortname)
     : product_shortname_(product_shortname),
       switches_(base::CommandLine::NO_PROGRAM) {}
 
diff --git a/chrome/chrome_cleaner/os/rebooter.h b/chrome/chrome_cleaner/os/rebooter.h
index 53b3940..406b864 100644
--- a/chrome/chrome_cleaner/os/rebooter.h
+++ b/chrome/chrome_cleaner/os/rebooter.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/command_line.h"
-#include "base/strings/string16.h"
 #include "chrome/chrome_cleaner/os/rebooter_api.h"
 
 namespace chrome_cleaner {
@@ -18,7 +17,7 @@
  public:
   static bool IsPostReboot();
 
-  explicit Rebooter(const base::string16& product_shortname);
+  explicit Rebooter(const std::wstring& product_shortname);
   ~Rebooter() override {}
 
   // RebooterAPI implementation.
@@ -32,7 +31,7 @@
   void UnregisterPostRebootRun() override;
 
  private:
-  base::string16 product_shortname_;
+  std::wstring product_shortname_;
   base::CommandLine switches_;
 };
 
diff --git a/chrome/chrome_cleaner/os/registry.cc b/chrome/chrome_cleaner/os/registry.cc
index 30ee69d8..04fa278 100644
--- a/chrome/chrome_cleaner/os/registry.cc
+++ b/chrome/chrome_cleaner/os/registry.cc
@@ -39,7 +39,7 @@
 }
 
 bool GetNativeKeyPath(const base::win::RegKey& key,
-                      base::string16* native_key_path) {
+                      std::wstring* native_key_path) {
   // This function uses a native API to determine the key path seen by the
   // kernel. See:
   // https://msdn.microsoft.com/en-us/library/windows/hardware/ff553373(v=vs.85).aspx
@@ -65,7 +65,7 @@
       reinterpret_cast<_KEY_NAME_INFORMATION*>(buffer.get());
   // The |NameLength| size is in bytes.
   *native_key_path =
-      base::string16(key_name->Name, key_name->NameLength / sizeof(wchar_t));
+      std::wstring(key_name->Name, key_name->NameLength / sizeof(wchar_t));
   return true;
 }
 
@@ -73,13 +73,13 @@
 // DCHECK'ed.
 RegKeyPath::RegKeyPath() : rootkey_(nullptr), wow64access_(0) {}
 
-RegKeyPath::RegKeyPath(HKEY rootkey, const base::string16& subkey)
+RegKeyPath::RegKeyPath(HKEY rootkey, const std::wstring& subkey)
     : RegKeyPath(rootkey, subkey, 0) {
   DCHECK(IsPredefinedRegistryHandle(rootkey));
 }
 
 RegKeyPath::RegKeyPath(HKEY rootkey,
-                       const base::string16& subkey,
+                       const std::wstring& subkey,
                        REGSAM wow64access)
     : rootkey_(rootkey), subkey_(subkey), wow64access_(wow64access) {
   DCHECK_NE(static_cast<HKEY>(nullptr), rootkey_);
@@ -136,8 +136,8 @@
   return true;
 }
 
-base::string16 RegKeyPath::FullPath() const {
-  base::string16 path = HKeyToString(rootkey());
+std::wstring RegKeyPath::FullPath() const {
+  std::wstring path = HKeyToString(rootkey());
   if (wow64access() == KEY_WOW64_32KEY)
     path += L":32";
   else if (wow64access() == KEY_WOW64_64KEY)
@@ -146,7 +146,7 @@
   return path;
 }
 
-bool RegKeyPath::GetNativeFullPath(base::string16* native_path) const {
+bool RegKeyPath::GetNativeFullPath(std::wstring* native_path) const {
   base::win::RegKey key;
   if (!Open(KEY_READ, &key))
     return false;
@@ -162,8 +162,8 @@
 bool RegKeyPath::IsEquivalent(const RegKeyPath& other) const {
   // For consistent behavior, stop immediately if either of the key paths is
   // not valid.
-  base::string16 key_path;
-  base::string16 other_key_path;
+  std::wstring key_path;
+  std::wstring other_key_path;
   if (!GetNativeFullPath(&key_path) ||
       !other.GetNativeFullPath(&other_key_path)) {
     return false;
diff --git a/chrome/chrome_cleaner/os/registry.h b/chrome/chrome_cleaner/os/registry.h
index bd9aac1c..7cc12635 100644
--- a/chrome/chrome_cleaner/os/registry.h
+++ b/chrome/chrome_cleaner/os/registry.h
@@ -11,8 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/strings/string16.h"
-
 namespace base {
 namespace win {
 class RegKey;
@@ -22,7 +20,7 @@
 namespace chrome_cleaner {
 
 bool GetNativeKeyPath(const base::win::RegKey& key,
-                      base::string16* native_key_path);
+                      std::wstring* native_key_path);
 
 // Returns true for predefined handles, such as NULL, INVALID_HANDLE_VALUE, and
 // for predefined registry root keys, such as HKEY_CLASSES_ROOT.
@@ -37,14 +35,14 @@
 class RegKeyPath {
  public:
   RegKeyPath();
-  RegKeyPath(HKEY rootkey, const base::string16& subkey);
+  RegKeyPath(HKEY rootkey, const std::wstring& subkey);
 
   // Create a path with an explicit wow64 view. Permissible values are
   // KEY_WOW64_32KEY, KEY_WOW64_64KEY and 0 (default based target architecture).
-  RegKeyPath(HKEY rootkey, const base::string16& subkey, REGSAM wow64access);
+  RegKeyPath(HKEY rootkey, const std::wstring& subkey, REGSAM wow64access);
 
   HKEY rootkey() const { return rootkey_; }
-  const base::string16& subkey() const { return subkey_; }
+  const std::wstring& subkey() const { return subkey_; }
   REGSAM wow64access() const { return wow64access_; }
 
   // Return whether the key exists (without creating it).
@@ -60,10 +58,10 @@
   bool Create(REGSAM access, base::win::RegKey* key) const;
 
   // Return the full path as a string. Intended for logging purposes only.
-  base::string16 FullPath() const;
+  std::wstring FullPath() const;
 
   // Return the native full path as a string.
-  bool GetNativeFullPath(base::string16* native_path) const;
+  bool GetNativeFullPath(std::wstring* native_path) const;
 
   // Test whether two paths are exactly identical. This returns false if the
   // same key is addressed with different Wow64 access bits. Behaviour is
@@ -87,7 +85,7 @@
 
  private:
   HKEY rootkey_;
-  base::string16 subkey_;
+  std::wstring subkey_;
   REGSAM wow64access_;
 };
 
diff --git a/chrome/chrome_cleaner/os/registry_unittest.cc b/chrome/chrome_cleaner/os/registry_unittest.cc
index 7a84ace..ea6e603 100644
--- a/chrome/chrome_cleaner/os/registry_unittest.cc
+++ b/chrome/chrome_cleaner/os/registry_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/strings/strcat.h"
-#include "base/strings/string16.h"
 #include "base/win/registry.h"
 #include "chrome/chrome_cleaner/os/system_util.h"
 #include "chrome/chrome_cleaner/strings/string_util.h"
@@ -148,7 +147,7 @@
 
 TEST(RegistryTests, GetNativeFullPath) {
   // The 'HKLM\\hardware' registry key doesn't have redirection.
-  base::string16 native_path;
+  std::wstring native_path;
   EXPECT_TRUE(RegKeyPath(HKEY_LOCAL_MACHINE, kHardwareKeyPath)
                   .GetNativeFullPath(&native_path));
   EXPECT_TRUE(
@@ -163,14 +162,14 @@
       String16EqualsCaseInsensitive(native_path, kNativeHardwareKeyPath));
 
   // The 'HKLM\\software' registry key may have a redirection.
-  base::string16 native_path32;
+  std::wstring native_path32;
   EXPECT_TRUE(RegKeyPath(HKEY_LOCAL_MACHINE, kSoftwareKeyPath, KEY_WOW64_32KEY)
                   .GetNativeFullPath(&native_path32));
   EXPECT_TRUE(
       String16EqualsCaseInsensitive(native_path32, kNativeSoftwareKeyPath) ||
       String16EqualsCaseInsensitive(native_path32, kNativeSoftwareKeyPath32));
 
-  base::string16 native_path64;
+  std::wstring native_path64;
   EXPECT_TRUE(RegKeyPath(HKEY_LOCAL_MACHINE, kSoftwareKeyPath, KEY_WOW64_64KEY)
                   .GetNativeFullPath(&native_path64));
   EXPECT_TRUE(
@@ -178,7 +177,7 @@
 }
 
 TEST(RegistryTests, GetNativeFullPathUpCase) {
-  base::string16 native_path32;
+  std::wstring native_path32;
   EXPECT_TRUE(
       RegKeyPath(HKEY_LOCAL_MACHINE, kSoftwareKeyPathUpCase, KEY_WOW64_32KEY)
           .GetNativeFullPath(&native_path32));
diff --git a/chrome/chrome_cleaner/os/registry_util.cc b/chrome/chrome_cleaner/os/registry_util.cc
index e9670be4..a871482 100644
--- a/chrome/chrome_cleaner/os/registry_util.cc
+++ b/chrome/chrome_cleaner/os/registry_util.cc
@@ -12,7 +12,6 @@
 #include "base/base_paths.h"
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -42,10 +41,10 @@
 // Split the pattern into path components. For example, with the pattern
 // 'ab??/x*/abc', |head| receives the component 'ab??' and |rest| receives the
 // remaining components 'x*/abc'.
-void ExtractHeadingSubkeyComponent(const base::string16& pattern,
+void ExtractHeadingSubkeyComponent(const std::wstring& pattern,
                                    const wchar_t escape_char,
-                                   base::string16* head,
-                                   base::string16* rest) {
+                                   std::wstring* head,
+                                   std::wstring* rest) {
   DCHECK(head);
   DCHECK(rest);
 
@@ -73,11 +72,11 @@
 // the wow64access masks for each existing path.
 void CollectMatchingRegistryPathsRecursive(
     HKEY hkey,
-    const base::string16& key_path,
-    const base::string16& pattern,
+    const std::wstring& key_path,
+    const std::wstring& pattern,
     const wchar_t escape_char,
     REGSAM wow64access,
-    std::map<base::string16, REGSAM>* path_masks) {
+    std::map<std::wstring, REGSAM>* path_masks) {
   DCHECK(path_masks);
 
   if (pattern.empty()) {
@@ -87,12 +86,12 @@
   }
 
   // Extract the first key_path component of the pattern.
-  base::string16 subkey_pattern;
-  base::string16 remaining_pattern;
+  std::wstring subkey_pattern;
+  std::wstring remaining_pattern;
   ExtractHeadingSubkeyComponent(pattern, escape_char, &subkey_pattern,
                                 &remaining_pattern);
 
-  base::string16 current_prefix;
+  std::wstring current_prefix;
   if (!key_path.empty())
     current_prefix = key_path + kRegistrySubkeyDelimiter;
 
@@ -110,7 +109,7 @@
   base::win::RegistryKeyIterator subkeys_it(hkey, key_path.c_str(),
                                             wow64access);
   for (; subkeys_it.Valid(); ++subkeys_it) {
-    base::string16 subkey_name = subkeys_it.Name();
+    std::wstring subkey_name = subkeys_it.Name();
     if (String16WildcardMatchInsensitive(subkey_name, subkey_pattern,
                                          escape_char)) {
       CollectMatchingRegistryPathsRecursive(hkey, current_prefix + subkey_name,
@@ -141,7 +140,7 @@
 const wchar_t kChromiumPoliciesAllowlistKeyPath[] =
     L"software\\policies\\chromium\\ExtensionInstallAllowlist";
 
-base::string16 RegistryValueTypeToString(DWORD value_type) {
+std::wstring RegistryValueTypeToString(DWORD value_type) {
   switch (value_type) {
     case REG_BINARY:
       return L"REG_BINARY";
@@ -168,9 +167,9 @@
 }
 
 void CollectMatchingRegistryNames(const base::win::RegKey& key,
-                                  const base::string16& pattern,
+                                  const std::wstring& pattern,
                                   const wchar_t escape_char,
-                                  std::vector<base::string16>* names) {
+                                  std::vector<std::wstring>* names) {
   DCHECK(names);
 
   // If there is no wild-card, return the pattern as-is.
@@ -214,14 +213,14 @@
 }
 
 void CollectMatchingRegistryPaths(HKEY hkey,
-                                  const base::string16& pattern,
+                                  const std::wstring& pattern,
                                   const wchar_t escape_char,
                                   std::vector<RegKeyPath>* key_paths) {
   DCHECK(key_paths);
   // We can query for key reflection, but not redirection. To avoid many special
   // cases here about which keys are remapped, we scan the Win32 and Win64 space
   // independently and remove duplicates after the fact.
-  std::map<base::string16, REGSAM> key_path_masks;
+  std::map<std::wstring, REGSAM> key_path_masks;
   if (!NameContainsWildcards(pattern)) {
     // If there is no wild-card, just check whether the key exists.
     if (RegKeyPath(hkey, pattern.c_str(), KEY_WOW64_32KEY).Exists())
@@ -257,7 +256,7 @@
 
 bool ReadRegistryValue(const base::win::RegKey& reg_key,
                        const wchar_t* value_name,
-                       base::string16* content,
+                       std::wstring* content,
                        uint32_t* content_type,
                        RegistryError* error) {
   DWORD content_bytes = 0;
@@ -303,7 +302,7 @@
   // Accept empty content.
   if (content_bytes == 0) {
     if (content)
-      *content = base::string16();
+      *content = std::wstring();
     if (content_type)
       *content_type = type;
     if (error)
@@ -314,8 +313,8 @@
   if (content) {
     // For non string types, simply convert the value to a string.
     if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) {
-      const base::string16::value_type* char16_buffer =
-          reinterpret_cast<base::string16::value_type*>(&buffer[0]);
+      const std::wstring::value_type* char16_buffer =
+          reinterpret_cast<std::wstring::value_type*>(&buffer[0]);
       GetRegistryValueAsString(char16_buffer, content_bytes, type, content);
     } else {
       // We may need to fix the null termination of the string read from the
@@ -340,9 +339,9 @@
       DCHECK_LE(content_bytes, buffer.size());
 
       // Returns the content of the registry value.
-      const base::string16::value_type* char16_buffer =
-          reinterpret_cast<base::string16::value_type*>(&buffer[0]);
-      *content = base::string16(char16_buffer, content_bytes / 2 - 1);
+      const std::wstring::value_type* char16_buffer =
+          reinterpret_cast<std::wstring::value_type*>(&buffer[0]);
+      *content = std::wstring(char16_buffer, content_bytes / 2 - 1);
     }
   }
   if (content_type)
@@ -354,7 +353,7 @@
 
 bool ReadRegistryValue(const RegKeyPath& key_path,
                        const wchar_t* value_name,
-                       base::string16* content,
+                       std::wstring* content,
                        uint32_t* content_type,
                        RegistryError* error) {
   DCHECK(value_name);
@@ -370,19 +369,19 @@
 }
 
 bool WriteRegistryValue(const wchar_t* value_name,
-                        const base::string16& content,
+                        const std::wstring& content,
                         uint32_t content_type,
                         base::win::RegKey* reg_key) {
   LONG success = reg_key->WriteValue(
       value_name, reinterpret_cast<const void*>(content.c_str()),
-      content.size() * sizeof(base::string16::value_type), content_type);
+      content.size() * sizeof(std::wstring::value_type), content_type);
   return success == ERROR_SUCCESS;
 }
 
 void GetRegistryValueAsString(const wchar_t* raw_content,
                               size_t raw_content_bytes,
                               DWORD value_type,
-                              base::string16* content) {
+                              std::wstring* content) {
   DCHECK(raw_content);
   DCHECK(content);
 
diff --git a/chrome/chrome_cleaner/os/registry_util.h b/chrome/chrome_cleaner/os/registry_util.h
index 4f099f6c..91f0790 100644
--- a/chrome/chrome_cleaner/os/registry_util.h
+++ b/chrome/chrome_cleaner/os/registry_util.h
@@ -9,10 +9,9 @@
 
 #include <stdint.h>
 
+#include <string>
 #include <vector>
 
-#include "base/strings/string16.h"
-
 namespace base {
 namespace win {
 class RegKey;
@@ -43,9 +42,9 @@
 // functions in base to manipulate user data obtained via the Windows API use
 // 16-bits strings.
 struct RegistryValue {
-  base::string16 key_path;
-  base::string16 value_name;
-  base::string16 data;
+  std::wstring key_path;
+  std::wstring value_name;
+  std::wstring data;
 };
 
 }  // namespace internal
@@ -71,19 +70,19 @@
 extern const wchar_t kChromiumPoliciesAllowlistKeyPath[];
 
 // Returns a string representation of the registry value type.
-base::string16 RegistryValueTypeToString(DWORD value_type);
+std::wstring RegistryValueTypeToString(DWORD value_type);
 
 // Enumerates matching value names from a registry key against a given pattern
 // with wild-cards.
 void CollectMatchingRegistryNames(const base::win::RegKey& key,
-                                  const base::string16& pattern,
+                                  const std::wstring& pattern,
                                   const wchar_t escape_char,
-                                  std::vector<base::string16>* names);
+                                  std::vector<std::wstring>* names);
 
 // Enumerates matching key paths from a registry key against a given pattern
 // with wild-cards. Returns a vector of fully qualified RegPath (i.e. wow64).
 void CollectMatchingRegistryPaths(HKEY hkey,
-                                  const base::string16& pattern,
+                                  const std::wstring& pattern,
                                   const wchar_t escape_char,
                                   std::vector<RegKeyPath>* key_paths);
 
@@ -93,7 +92,7 @@
 // |error| to indicate the type of error code.
 bool ReadRegistryValue(const base::win::RegKey& reg_key,
                        const wchar_t* value_name,
-                       base::string16* content,
+                       std::wstring* content,
                        uint32_t* content_type,
                        RegistryError* error);
 
@@ -102,14 +101,14 @@
 // set |error| to indicate the type of error code.
 bool ReadRegistryValue(const RegKeyPath& key_path,
                        const wchar_t* value_name,
-                       base::string16* content,
+                       std::wstring* content,
                        uint32_t* content_type,
                        RegistryError* error);
 
 // Write a registry value of type REG_SZ, REG_EXPAND_SZ or REG_MULTI_SZ. Return
 // false on failure.
 bool WriteRegistryValue(const wchar_t* value_name,
-                        const base::string16& content,
+                        const std::wstring& content,
                         uint32_t content_type,
                         base::win::RegKey* reg_key);
 
@@ -121,7 +120,7 @@
 void GetRegistryValueAsString(const wchar_t* raw_content,
                               size_t raw_content_bytes,
                               DWORD value_type,
-                              base::string16* content);
+                              std::wstring* content);
 
 }  // namespace chrome_cleaner
 
diff --git a/chrome/chrome_cleaner/os/registry_util_unittest.cc b/chrome/chrome_cleaner/os/registry_util_unittest.cc
index 8a67ca9..bec244c 100644
--- a/chrome/chrome_cleaner/os/registry_util_unittest.cc
+++ b/chrome/chrome_cleaner/os/registry_util_unittest.cc
@@ -80,7 +80,7 @@
   ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(L"Test2", kValue));
   ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(L"Test_3", kValue));
 
-  std::vector<base::string16> names;
+  std::vector<std::wstring> names;
   CollectMatchingRegistryNames(
       registry_key, L"Test*", PUPData::kRegistryPatternEscapeCharacter, &names);
   EXPECT_THAT(names, testing::ElementsAre(L"Test1", L"Test2", L"Test_3"));
@@ -135,7 +135,7 @@
   ASSERT_EQ(ERROR_SUCCESS, registry_key.WriteValue(
                                L"\uFFFF" ESCAPE_REGISTRY_STR("*"), kValue));
 
-  std::vector<base::string16> names;
+  std::vector<std::wstring> names;
   CollectMatchingRegistryNames(registry_key, ESCAPE_REGISTRY_STR("*"),
                                PUPData::kRegistryPatternEscapeCharacter,
                                &names);
@@ -321,7 +321,7 @@
   // Try to read back the registry key with invalid access rights.
   const RegKeyPath key_path(HKEY_LOCAL_MACHINE, kRegistryKeyPath);
   base::win::RegKey key;
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
   EXPECT_TRUE(key_path.Open(KEY_WRITE, &key));
   EXPECT_FALSE(
@@ -342,7 +342,7 @@
   base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
                             KEY_ALL_ACCESS);
 
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type = REG_NONE;
 
   EXPECT_FALSE(
@@ -357,7 +357,7 @@
   base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
                             KEY_ALL_ACCESS);
 
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
 
   // Write a string value and read it back.
@@ -380,7 +380,7 @@
   base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
                             KEY_ALL_ACCESS);
 
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
 
   // Write a string value and read it back.
@@ -400,7 +400,7 @@
   base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
                             KEY_ALL_ACCESS);
 
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
 
   // Write a multi-string value and read it back.
@@ -420,7 +420,7 @@
   base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
                             KEY_ALL_ACCESS);
 
-  base::string16 content;
+  std::wstring content;
 
   // Write a string value with null characters and read it back.
   EXPECT_EQ(ERROR_SUCCESS, reg_key.WriteValue(kValueName, kValueWithNull,
@@ -440,7 +440,7 @@
   // Write an empty string (0 byte) value and read it back.
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, kValueEmpty, 0, REG_SZ));
-  base::string16 content;
+  std::wstring content;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, nullptr, nullptr));
   EXPECT_EQ(0U, content.size());
@@ -452,10 +452,10 @@
   base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, kRegistryKeyPath,
                             KEY_ALL_ACCESS);
 
-  base::string16 content;
+  std::wstring content;
 
   // Write a huge string to the registry value and read it back.
-  base::string16 huge_content(4096, 'x');
+  std::wstring huge_content(4096, 'x');
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, huge_content.c_str()));
   EXPECT_TRUE(
@@ -472,7 +472,7 @@
   // Write a DWORD value.
   EXPECT_EQ(ERROR_SUCCESS, reg_key.WriteValue(kValueName, kDWORDValue));
 
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, &content_type, nullptr));
@@ -489,7 +489,7 @@
   // Write a binary value.
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, kValue, sizeof(kValue), REG_BINARY));
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, &content_type, nullptr));
@@ -505,7 +505,7 @@
 
   // Write a binary value.
   EXPECT_EQ(ERROR_SUCCESS, reg_key.WriteValue(kValueName, "a", 1, REG_BINARY));
-  base::string16 content;
+  std::wstring content;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, nullptr, nullptr));
   EXPECT_EQ(L"61", content);
@@ -521,7 +521,7 @@
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, kOddSizeEntryString,
                                sizeof(kOddSizeEntryString), REG_SZ));
-  base::string16 content;
+  std::wstring content;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, nullptr, nullptr));
   EXPECT_EQ(kExpectedOddSizeEntryString, content);
@@ -537,7 +537,7 @@
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, kSingleNullCharString,
                                sizeof(kSingleNullCharString), REG_SZ));
-  base::string16 content;
+  std::wstring content;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, nullptr, nullptr));
   EXPECT_EQ(kExpectedSingleOrNoNullCharString, content);
@@ -553,7 +553,7 @@
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, kNoNullCharString,
                                sizeof(kNoNullCharString), REG_SZ));
-  base::string16 content;
+  std::wstring content;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, nullptr, nullptr));
   EXPECT_EQ(kExpectedSingleOrNoNullCharString, content);
@@ -569,7 +569,7 @@
   EXPECT_EQ(ERROR_SUCCESS,
             reg_key.WriteValue(kValueName, kNullOddSizeEntryString,
                                sizeof(kNullOddSizeEntryString), REG_SZ));
-  base::string16 content;
+  std::wstring content;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, nullptr, nullptr));
   EXPECT_EQ(0, ::memcmp(content.c_str(), kExpectedNullOddSizeEntryString,
@@ -584,11 +584,11 @@
                             KEY_ALL_ACCESS);
 
   // Write a value with NUL characters.
-  base::string16 source(kValueWithNull, base::size(kValueWithNull) - 1);
+  std::wstring source(kValueWithNull, base::size(kValueWithNull) - 1);
   EXPECT_TRUE(WriteRegistryValue(kValueName, source, REG_SZ, &reg_key));
 
   // Read back the value.
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, &content_type, nullptr));
@@ -603,11 +603,11 @@
                             KEY_ALL_ACCESS);
 
   // Write a value with unicode characters.
-  base::string16 source(kUnicodeValue, base::size(kUnicodeValue) - 1);
+  std::wstring source(kUnicodeValue, base::size(kUnicodeValue) - 1);
   EXPECT_TRUE(WriteRegistryValue(kValueName, source, REG_SZ, &reg_key));
 
   // Read back the value.
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, &content_type, nullptr));
@@ -622,12 +622,12 @@
                             KEY_ALL_ACCESS);
 
   // Write a value with an invalid character.
-  base::string16 source(kInvalidUnicodeValue,
-                        base::size(kInvalidUnicodeValue) - 1);
+  std::wstring source(kInvalidUnicodeValue,
+                      base::size(kInvalidUnicodeValue) - 1);
   EXPECT_TRUE(WriteRegistryValue(kValueName, source, REG_SZ, &reg_key));
 
   // Read back the value.
-  base::string16 content;
+  std::wstring content;
   uint32_t content_type;
   EXPECT_TRUE(
       ReadRegistryValue(reg_key, kValueName, &content, &content_type, nullptr));
@@ -636,8 +636,8 @@
 }
 
 TEST(RegistryUtilTests, GetRegistryValueAsStringRegularString) {
-  base::string16 input_value(kUnicodeValue, base::size(kUnicodeValue) - 1);
-  base::string16 output_value;
+  std::wstring input_value(kUnicodeValue, base::size(kUnicodeValue) - 1);
+  std::wstring output_value;
 
   GetRegistryValueAsString(input_value.c_str(),
                            input_value.size() * sizeof(wchar_t), REG_SZ,
@@ -647,8 +647,8 @@
 }
 
 TEST(RegistryUtilTests, GetRegistryValueAsStringDword) {
-  base::string16 input_value(kDWORDRawValue, sizeof(kDWORDValue));
-  base::string16 output_value;
+  std::wstring input_value(kDWORDRawValue, sizeof(kDWORDValue));
+  std::wstring output_value;
 
   GetRegistryValueAsString(input_value.c_str(),
                            input_value.size() * sizeof(wchar_t), REG_DWORD,
@@ -658,7 +658,7 @@
 }
 
 TEST(RegistryUtilTests, GetRegistryValueAsStringFakeBinary) {
-  base::string16 output_value;
+  std::wstring output_value;
 
   GetRegistryValueAsString(kValue, sizeof(kValue), REG_BINARY, &output_value);
 
@@ -666,7 +666,7 @@
 }
 
 TEST(RegistryUtilTests, GetRegistryValueAsStringRealBinary) {
-  base::string16 output_value;
+  std::wstring output_value;
 
   GetRegistryValueAsString(reinterpret_cast<const wchar_t*>(kBytesValue),
                            base::size(kBytesValue), REG_BINARY, &output_value);
@@ -675,7 +675,7 @@
 }
 
 TEST(RegistryUtilTests, GetRegistryValueAsStringSmallBinaries) {
-  base::string16 output_value;
+  std::wstring output_value;
   GetRegistryValueAsString(reinterpret_cast<const wchar_t*>("a"), 1, REG_BINARY,
                            &output_value);
   EXPECT_EQ(L"61", output_value);
diff --git a/chrome/chrome_cleaner/os/system_util.h b/chrome/chrome_cleaner/os/system_util.h
index 0d201b2..ea0d5db 100644
--- a/chrome/chrome_cleaner/os/system_util.h
+++ b/chrome/chrome_cleaner/os/system_util.h
@@ -7,9 +7,9 @@
 
 #include <windows.h>
 
+#include <string>
 #include <vector>
 
-#include "base/strings/string16.h"
 #include "chrome/chrome_cleaner/os/scoped_service_handle.h"
 
 namespace chrome_cleaner {
@@ -17,8 +17,8 @@
 // Based on ENUM_SERVICE_STATUS_PROCESSW from
 // https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_enum_service_status_processw
 struct ServiceStatus {
-  base::string16 service_name;
-  base::string16 display_name;
+  std::wstring service_name;
+  std::wstring display_name;
   SERVICE_STATUS_PROCESS service_status_process;
 };
 
diff --git a/chrome/chrome_cleaner/os/system_util_cleaner.cc b/chrome/chrome_cleaner/os/system_util_cleaner.cc
index 8e10f09..023a7a1 100644
--- a/chrome/chrome_cleaner/os/system_util_cleaner.cc
+++ b/chrome/chrome_cleaner/os/system_util_cleaner.cc
@@ -12,6 +12,7 @@
 #include <shellapi.h>
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -21,7 +22,6 @@
 #include "base/process/process_info.h"
 #include "base/process/process_iterator.h"
 #include "base/stl_util.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/threading/simple_thread.h"
 #include "base/win/scoped_com_initializer.h"
@@ -79,8 +79,8 @@
       return;
     }
 
-    const base::string16 file = command_line_.GetProgram().value();
-    const base::string16 arguments = command_line_.GetArgumentsString();
+    const std::wstring file = command_line_.GetProgram().value();
+    const std::wstring arguments = command_line_.GetArgumentsString();
 
     SHELLEXECUTEINFO shex_info = {};
     shex_info.cbSize = sizeof(shex_info);
diff --git a/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc b/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc
index a49242f3..19229f1 100644
--- a/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc
+++ b/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc
@@ -23,7 +23,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/test/scoped_command_line.h"
 #include "base/test/scoped_path_override.h"
diff --git a/chrome/chrome_cleaner/os/task_scheduler.cc b/chrome/chrome_cleaner/os/task_scheduler.cc
index 0bc353d..c8280af 100644
--- a/chrome/chrome_cleaner/os/task_scheduler.cc
+++ b/chrome/chrome_cleaner/os/task_scheduler.cc
@@ -10,6 +10,8 @@
 #include <taskschd.h>
 #include <wrl/client.h>
 
+#include <string>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
@@ -17,7 +19,6 @@
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "base/strings/strcat.h"
-#include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/win/scoped_bstr.h"
@@ -49,7 +50,7 @@
 const size_t kDeleteRetryDelayInMs = 100;
 
 // Return |timestamp| in the following string format YYYY-MM-DDTHH:MM:SS.
-base::string16 GetTimestampString(const base::Time& timestamp) {
+std::wstring GetTimestampString(const base::Time& timestamp) {
   base::Time::Exploded exploded_time;
   // The Z timezone info at the end of the string means UTC.
   timestamp.UTCExplode(&exploded_time);
@@ -269,7 +270,7 @@
     return is_enabled == VARIANT_TRUE;
   }
 
-  bool GetTaskNameList(std::vector<base::string16>* task_names) override {
+  bool GetTaskNameList(std::vector<std::wstring>* task_names) override {
     DCHECK(task_names);
     if (!root_task_folder_)
       return false;
@@ -494,7 +495,7 @@
         if (base::CommandLine::ForCurrentProcess()->HasSwitch(
                 kLogUploadRetryIntervalSwitch)) {
           // String format: PT%lsM
-          const base::string16 interval_switch = base::StrCat(
+          const std::wstring interval_switch = base::StrCat(
               {L"PT",
                base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
                    kLogUploadRetryIntervalSwitch),
@@ -709,7 +710,7 @@
         Next();
         return;
       }
-      name_ = base::string16(task_name_bstr.Get() ? task_name_bstr.Get() : L"");
+      name_ = std::wstring(task_name_bstr.Get() ? task_name_bstr.Get() : L"");
     }
 
     // Detach the currently active task and pass ownership to the caller.
@@ -724,13 +725,13 @@
       return result;
     }
 
-    const base::string16& name() const { return name_; }
+    const std::wstring& name() const { return name_; }
     bool done() const { return done_; }
 
    private:
     Microsoft::WRL::ComPtr<IRegisteredTaskCollection> tasks_;
     Microsoft::WRL::ComPtr<IRegisteredTask> task_;
-    base::string16 name_;
+    std::wstring name_;
     long task_index_ = -1;  // NOLINT, API requires a long.
     long num_tasks_ = 0;    // NOLINT, API requires a long.
     bool done_ = false;
@@ -750,15 +751,14 @@
   }
 
   // Return the description of the task.
-  HRESULT GetTaskDescription(IRegisteredTask* task,
-                             base::string16* description) {
+  HRESULT GetTaskDescription(IRegisteredTask* task, std::wstring* description) {
     DCHECK(task);
     DCHECK(description);
 
     base::win::ScopedBstr task_name_bstr;
     HRESULT hr = task->get_Name(task_name_bstr.Receive());
-    base::string16 task_name =
-        base::string16(task_name_bstr.Get() ? task_name_bstr.Get() : L"");
+    std::wstring task_name =
+        std::wstring(task_name_bstr.Get() ? task_name_bstr.Get() : L"");
     if (FAILED(hr)) {
       LOG(ERROR) << "Failed to get task name";
     }
@@ -787,7 +787,7 @@
       return hr;
     }
     *description =
-        base::string16(raw_description.Get() ? raw_description.Get() : L"");
+        std::wstring(raw_description.Get() ? raw_description.Get() : L"");
     return ERROR_SUCCESS;
   }
 
@@ -887,7 +887,7 @@
           {base::FilePath(application_path.Get() ? application_path.Get()
                                                  : L""),
            base::FilePath(working_dir.Get() ? working_dir.Get() : L""),
-           base::string16(parameters.Get() ? parameters.Get() : L"")});
+           std::wstring(parameters.Get() ? parameters.Get() : L"")});
     }
     return success;
   }
@@ -980,7 +980,7 @@
   bool IsTaskEnabled(const wchar_t* task_name) override {
     return delegate_->IsTaskEnabled(task_name);
   }
-  bool GetTaskNameList(std::vector<base::string16>* task_names) override {
+  bool GetTaskNameList(std::vector<std::wstring>* task_names) override {
     return delegate_->GetTaskNameList(task_names);
   }
   bool GetTaskInfo(const wchar_t* task_name, TaskInfo* info) override {
diff --git a/chrome/chrome_cleaner/os/task_scheduler.h b/chrome/chrome_cleaner/os/task_scheduler.h
index 479e689..29dfac6 100644
--- a/chrome/chrome_cleaner/os/task_scheduler.h
+++ b/chrome/chrome_cleaner/os/task_scheduler.h
@@ -56,7 +56,7 @@
   struct TaskExecAction {
     base::FilePath application_path;
     base::FilePath working_dir;
-    base::string16 arguments;
+    std::wstring arguments;
   };
 
   // Detailed description of a scheduled task. This type is returned by the
@@ -69,9 +69,9 @@
     TaskInfo& operator=(const TaskInfo&);
     TaskInfo& operator=(TaskInfo&&);
 
-    base::string16 name;
+    std::wstring name;
     // Description (Vista and later) or comment (XP and earlier) of the task.
-    base::string16 description;
+    std::wstring description;
     // On Windows Vista and later, a scheduled task can have more than one
     // action associated with it and actions can be of types other than
     // executables (for example, sending emails). This list however contains
@@ -124,7 +124,7 @@
   virtual bool IsTaskEnabled(const wchar_t* task_name) = 0;
 
   // List all currently registered scheduled tasks.
-  virtual bool GetTaskNameList(std::vector<base::string16>* task_names) = 0;
+  virtual bool GetTaskNameList(std::vector<std::wstring>* task_names) = 0;
 
   // Return detailed information about a task. Return true if no errors were
   // encountered. On error, the struct is left unmodified.
diff --git a/chrome/chrome_cleaner/os/task_scheduler_unittest.cc b/chrome/chrome_cleaner/os/task_scheduler_unittest.cc
index a5d240e..471da601 100644
--- a/chrome/chrome_cleaner/os/task_scheduler_unittest.cc
+++ b/chrome/chrome_cleaner/os/task_scheduler_unittest.cc
@@ -7,6 +7,7 @@
 #include <taskschd.h>
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
@@ -14,7 +15,6 @@
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/strcat.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
@@ -101,7 +101,7 @@
 
   // Create a unique name for a shared event to be waited for in this process
   // and signaled in the test process to confirm it was scheduled and ran.
-  const base::string16 event_name =
+  const std::wstring event_name =
       base::StrCat({kTestProcessExecutableName, L"-",
                     base::NumberToWString(::GetCurrentProcessId())});
   base::WaitableEvent event(base::win::ScopedHandle(
@@ -205,7 +205,7 @@
                                     TaskScheduler::TRIGGER_TYPE_HOURLY, false));
   EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName2));
 
-  std::vector<base::string16> task_names;
+  std::vector<std::wstring> task_names;
   EXPECT_TRUE(task_scheduler_->GetTaskNameList(&task_names));
   EXPECT_TRUE(base::Contains(task_names, kTaskName1));
   EXPECT_TRUE(base::Contains(task_names, kTaskName2));
@@ -226,7 +226,7 @@
 
   EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
 
-  std::vector<base::string16> task_names;
+  std::vector<std::wstring> task_names;
   EXPECT_TRUE(task_scheduler_->GetTaskNameList(&task_names));
   EXPECT_TRUE(base::Contains(task_names, kTaskName1));
 
diff --git a/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc b/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc
index eb007224..55ee6d2 100644
--- a/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc
+++ b/chrome/chrome_cleaner/parsers/broker/lnk_parser_sandbox_setup_unittest.cc
@@ -79,7 +79,7 @@
   base::win::ShortcutProperties shortcut_properties;
   shortcut_properties.set_target(not_lnk_file_path_);
   shortcut_properties.set_icon(not_lnk_file_path_, /*icon_index=*/0);
-  const base::string16 lnk_arguments = L"argument1 -f -t -a -o";
+  const std::wstring lnk_arguments = L"argument1 -f -t -a -o";
   shortcut_properties.set_arguments(lnk_arguments);
 
   base::win::ScopedHandle lnk_file_handle = CreateAndOpenShortcutInTempDir(
diff --git a/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.cc b/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.cc
index 0ead861..8b75cc4 100644
--- a/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.cc
+++ b/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.cc
@@ -19,22 +19,22 @@
 
 // It may be possible that the return value of GURL.host() is %-scaped, use
 // this function to get the ASCII version.
-base::string16 GetUnescapedHost(GURL url) {
+std::wstring GetUnescapedHost(GURL url) {
   std::string url_host = url.host();
 
   url::RawCanonOutputT<wchar_t> unescaped_url_host;
   url::DecodeURLEscapeSequences(url_host.c_str(), url_host.length(),
                                 url::DecodeURLMode::kUTF8OrIsomorphic,
                                 &unescaped_url_host);
-  return base::string16(unescaped_url_host.data(), unescaped_url_host.length());
+  return std::wstring(unescaped_url_host.data(), unescaped_url_host.length());
 }
 
 // Tries to parse the url string using GURL and returns the concatenation of
 // the scheme and the host. If the url is not valid it returns the same string
 // that was provided. If the url has no scheme, http:// is assumed.
-base::string16 SanitizeUrl(const base::string16& possible_url) {
+std::wstring SanitizeUrl(const std::wstring& possible_url) {
   bool has_scheme = (possible_url.find(L"://") != std::string::npos);
-  base::string16 scheme = (has_scheme) ? L"" : L"http://";
+  std::wstring scheme = (has_scheme) ? L"" : L"http://";
   GURL url(scheme + possible_url);
 
   if (!url.is_valid())
@@ -49,7 +49,7 @@
 }
 }  // namespace
 
-std::vector<base::string16> SanitizeArguments(const base::string16& arguments) {
+std::vector<std::wstring> SanitizeArguments(const std::wstring& arguments) {
   // We prepend a dummy to the string because it takes the first element as the
   // executable path.
   const base::CommandLine command_line =
@@ -57,7 +57,7 @@
 
   const base::CommandLine::SwitchMap& switches = command_line.GetSwitches();
 
-  std::vector<base::string16> sanitized_arguments;
+  std::vector<std::wstring> sanitized_arguments;
   for (auto it = switches.begin(); it != switches.end(); it++) {
     sanitized_arguments.push_back(
         L"--" + base::UTF8ToWide(it->first) +
diff --git a/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.h b/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.h
index 1e56f345..79e8ffa 100644
--- a/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.h
+++ b/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer.h
@@ -6,15 +6,14 @@
 #define CHROME_CHROME_CLEANER_PARSERS_PARSER_UTILS_COMMAND_LINE_ARGUMENTS_SANITIZER_H_
 
 #include <cstring>
+#include <string>
 #include <vector>
 
-#include "base/strings/string16.h"
-
 namespace chrome_cleaner {
 
 // Receives a string of space separated command line arguments, sanitizes
 // each one of them and returns them inside a vector.
-std::vector<base::string16> SanitizeArguments(const base::string16& arguments);
+std::vector<std::wstring> SanitizeArguments(const std::wstring& arguments);
 
 }  // namespace chrome_cleaner
 
diff --git a/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer_unittest.cc b/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer_unittest.cc
index b14d6ce..80ff368 100644
--- a/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer_unittest.cc
+++ b/chrome/chrome_cleaner/parsers/parser_utils/command_line_arguments_sanitizer_unittest.cc
@@ -6,10 +6,11 @@
 
 #include <shlobj.h>
 
+#include <string>
+
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
-#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "chrome/chrome_cleaner/os/file_path_sanitization.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -18,14 +19,14 @@
 namespace chrome_cleaner {
 
 TEST(CommandLineArgumentsSanitizerTest, SanitizeURLArgumentsWithScheme) {
-  const base::string16 kTestArguments =
+  const std::wstring kTestArguments =
       base::JoinString({L"http://www.somesite.com/hello/this/is/private",
                         L"ftp://some-ftp-site.com/private/data",
                         L"--some-flag=http://somesite.com.mx/private/data"},
                        L" ");
-  std::vector<base::string16> sanitized_arguments =
+  std::vector<std::wstring> sanitized_arguments =
       SanitizeArguments(kTestArguments);
-  std::vector<base::string16> expected_arguments = {
+  std::vector<std::wstring> expected_arguments = {
       L"--some-flag=http://somesite.com.mx", L"http://www.somesite.com",
       L"ftp://some-ftp-site.com"};
   EXPECT_THAT(sanitized_arguments,
@@ -33,13 +34,13 @@
 }
 
 TEST(CommandLineArgumentsSanitizerTest, SanitizeURLArgumentsWithoutScheme) {
-  const base::string16 kTestArguments = base::JoinString(
+  const std::wstring kTestArguments = base::JoinString(
       {L"www.somesite.com/hello/this/is/private", L"somesite.com/private/data",
        L"--some-flag=somesite.com/private/data"},
       L" ");
-  std::vector<base::string16> sanitized_arguments =
+  std::vector<std::wstring> sanitized_arguments =
       SanitizeArguments(kTestArguments);
-  std::vector<base::string16> expected_arguments = {
+  std::vector<std::wstring> expected_arguments = {
       L"--some-flag=http://somesite.com", L"http://www.somesite.com",
       L"http://somesite.com"};
   EXPECT_THAT(sanitized_arguments,
@@ -49,18 +50,18 @@
 TEST(CommandLineArgumentsSanitizerTest, SanitizeFilePaths) {
   base::FilePath user_path;
   base::PathService::Get(CsidlToPathServiceKey(CSIDL_APPDATA), &user_path);
-  const base::string16 kSanitizedUserPath = L"CSIDL_PROFILE\\appdata\\roaming";
+  const std::wstring kSanitizedUserPath = L"CSIDL_PROFILE\\appdata\\roaming";
 
-  const base::string16 kTestArguments = base::JoinString(
+  const std::wstring kTestArguments = base::JoinString(
       {user_path.value(), L" local/relative/path",
        L"--flag=" + user_path.value(), L" --another-flag=local/relative/path",
        L"--spaces=\"C:\\folder \\with \\spaces\"",
        L"--unicode=C:\\unicode\x0278\\folder"},
       L" ");
 
-  std::vector<base::string16> sanitized_arguments =
+  std::vector<std::wstring> sanitized_arguments =
       SanitizeArguments(kTestArguments);
-  std::vector<base::string16> expected_arguments = {
+  std::vector<std::wstring> expected_arguments = {
       L"--another-flag=local/relative/path",
       L"--flag=" + kSanitizedUserPath,
       L"--spaces=c:\\folder \\with \\spaces",
@@ -72,11 +73,11 @@
 }
 
 TEST(CommandLineArgumentsSanitizerTest, NotUrlOrFilePathArguments) {
-  const base::string16 kTestArguments =
+  const std::wstring kTestArguments =
       L"--some-flag not-a-url --some-other-flag=notaurl";
-  std::vector<base::string16> sanitized_arguments =
+  std::vector<std::wstring> sanitized_arguments =
       SanitizeArguments(kTestArguments);
-  std::vector<base::string16> expected_arguments = {
+  std::vector<std::wstring> expected_arguments = {
       L"--some-flag", L"--some-other-flag=notaurl", L"not-a-url"};
   EXPECT_THAT(sanitized_arguments,
               testing::UnorderedElementsAreArray(expected_arguments));
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/fake_shortcut_parser.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/fake_shortcut_parser.cc
index 47983327..e9d4624 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/fake_shortcut_parser.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/fake_shortcut_parser.cc
@@ -4,10 +4,11 @@
 
 #include "chrome/chrome_cleaner/parsers/shortcut_parser/broker/fake_shortcut_parser.h"
 
+#include <string>
+
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "base/strings/string16.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/win/scoped_handle.h"
 #include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h"
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc
index c2fa4792..43c067b 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.cc
@@ -6,13 +6,14 @@
 
 #include <stdio.h>
 
+#include <string>
+
 #include "base/bind.h"
 #include "base/files/file.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
-#include "base/strings/string16.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "base/win/scoped_handle.h"
@@ -107,9 +108,9 @@
     scoped_refptr<ParseTasksRemainingCounter> counter,
     std::vector<ShortcutInformation>* found_shortcuts,
     mojom::LnkParsingResult parsing_result,
-    const base::Optional<base::string16>& optional_file_path,
-    const base::Optional<base::string16>& optional_command_line_arguments,
-    const base::Optional<base::string16>& optional_icon_location) {
+    const base::Optional<std::wstring>& optional_file_path,
+    const base::Optional<std::wstring>& optional_command_line_arguments,
+    const base::Optional<std::wstring>& optional_icon_location) {
   ShortcutInformation parsed_shortcut;
   parsed_shortcut.lnk_path = lnk_path;
   if (parsing_result == mojom::LnkParsingResult::SUCCESS) {
@@ -124,7 +125,7 @@
     if (optional_icon_location.has_value())
       parsed_shortcut.icon_location = optional_icon_location.value();
 
-    const base::string16 kChromeLnkName = L"Google Chrome.lnk";
+    const std::wstring kChromeLnkName = L"Google Chrome.lnk";
     if (chrome_exe_locations.Contains(
             base::FilePath(parsed_shortcut.icon_location)) ||
         lnk_path.BaseName().value() == kChromeLnkName) {
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h
index 651cb90b..ef54c9c 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h
@@ -43,9 +43,9 @@
       scoped_refptr<ParseTasksRemainingCounter> counter,
       std::vector<ShortcutInformation>* found_shortcuts,
       mojom::LnkParsingResult parsing_result,
-      const base::Optional<base::string16>& optional_file_path,
-      const base::Optional<base::string16>& optional_command_line_arguments,
-      const base::Optional<base::string16>& optional_icon_location);
+      const base::Optional<std::wstring>& optional_file_path,
+      const base::Optional<std::wstring>& optional_command_line_arguments,
+      const base::Optional<std::wstring>& optional_icon_location);
 
   base::Lock lock_;
   MojoTaskRunner* mojo_task_runner_;
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc
index 0c5368f..cc77d097a 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser_unittest.cc
@@ -29,7 +29,7 @@
 // Arbitrary value of temp_dirs.
 constexpr unsigned int kDirQuantity = 5;
 
-const base::string16 kLnkArguments = L"-a -b -c -d GenericExample";
+const std::wstring kLnkArguments = L"-a -b -c -d GenericExample";
 
 class LoggedParserSandboxSetupHooks : public ParserSandboxSetupHooks {
  public:
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/shortcut_parser_api.h b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/shortcut_parser_api.h
index d18d839..f91529cf 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/broker/shortcut_parser_api.h
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/broker/shortcut_parser_api.h
@@ -23,9 +23,9 @@
   ~ShortcutInformation();
 
   base::FilePath lnk_path;
-  base::string16 target_path;
-  base::string16 command_line_arguments;
-  base::string16 icon_location;
+  std::wstring target_path;
+  std::wstring command_line_arguments;
+  std::wstring icon_location;
 };
 
 typedef base::OnceCallback<void(std::vector<ShortcutInformation>)>
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.cc
index ad51889..d360cf2 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.cc
@@ -37,7 +37,7 @@
 
 bool CheckParsedShortcut(const ParsedLnkFile& parsed_shortcut,
                          base::FilePath expected_target_path,
-                         base::string16 expected_arguments,
+                         std::wstring expected_arguments,
                          base::FilePath expected_icon_location) {
   base::FilePath parsed_file_path(parsed_shortcut.target_path);
   return PathEqual(parsed_file_path, expected_target_path) &&
@@ -50,9 +50,9 @@
     mojom::LnkParsingResult* out_result_code,
     base::OnceClosure callback,
     mojom::LnkParsingResult result_code,
-    const base::Optional<base::string16>& optional_file_path,
-    const base::Optional<base::string16>& optional_command_line_arguments,
-    const base::Optional<base::string16>& optional_icon_location) {
+    const base::Optional<std::wstring>& optional_file_path,
+    const base::Optional<std::wstring>& optional_command_line_arguments,
+    const base::Optional<std::wstring>& optional_icon_location) {
   *out_result_code = result_code;
   if (optional_file_path.has_value())
     out_parsed_shortcut->target_path = optional_file_path.value();
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.h b/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.h
index a02b401..9e23dd0 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.h
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.h
@@ -25,16 +25,16 @@
 
 bool CheckParsedShortcut(const ParsedLnkFile& parsed_shortcut,
                          base::FilePath expected_target_path,
-                         base::string16 expected_arguments,
+                         std::wstring expected_arguments,
                          base::FilePath expected_icon_location);
 void OnLnkParseDone(
     ParsedLnkFile* out_parsed_shortcut,
     mojom::LnkParsingResult* out_result_code,
     base::OnceClosure callback,
     mojom::LnkParsingResult result_code,
-    const base::Optional<base::string16>& optional_file_path,
-    const base::Optional<base::string16>& optional_command_line_arguments,
-    const base::Optional<base::string16>& optional_icon_location);
+    const base::Optional<std::wstring>& optional_file_path,
+    const base::Optional<std::wstring>& optional_command_line_arguments,
+    const base::Optional<std::wstring>& optional_icon_location);
 
 }  // namespace chrome_cleaner
 
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.cc
index dfad246..b72f7e11 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.cc
@@ -7,13 +7,13 @@
 #include <windows.h>
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_handle.h"
 
@@ -51,7 +51,7 @@
 
 bool NullTerminatedASCIIBufferToString16(const std::vector<BYTE>& buffer,
                                          DWORD* current_byte,
-                                         base::string16* parsed_string) {
+                                         std::wstring* parsed_string) {
   const DWORD string_start = *current_byte;
   const int kMaxCharactersToRead = buffer.size() - *current_byte;
   int string_size =
@@ -74,7 +74,7 @@
 
 bool NullTerminatedUtf16BufferToString16(const std::vector<BYTE>& buffer,
                                          DWORD* current_byte,
-                                         base::string16* parsed_string) {
+                                         std::wstring* parsed_string) {
   const DWORD string_start = *current_byte;
   const int kMaxWideCharactersToRead =
       (buffer.size() - *current_byte) / sizeof(wchar_t);
@@ -102,7 +102,7 @@
 bool NullTerminatedStringToString16(const std::vector<BYTE>& buffer,
                                     bool is_unicode,
                                     DWORD* current_byte,
-                                    base::string16* parsed_string) {
+                                    std::wstring* parsed_string) {
   if (*current_byte >= buffer.size()) {
     LOG(ERROR) << "Error parsing null terminated string";
     return false;
@@ -139,7 +139,7 @@
 // and then moves the value of current_byte to the end of it.
 bool ReadUtf16StringStructure(const std::vector<BYTE>& buffer,
                               DWORD* current_byte,
-                              base::string16* parsed_string) {
+                              std::wstring* parsed_string) {
   uint16_t string_size;
   if (!ReadUnsignedShort(buffer, current_byte, &string_size)) {
     LOG(ERROR) << "Error reading string structure";
@@ -293,7 +293,7 @@
 
   current_byte = structure_beginning + path_prefix_offset;
 
-  base::string16 prefix_string;
+  std::wstring prefix_string;
   if (!NullTerminatedStringToString16(file_buffer, is_unicode, &current_byte,
                                       &prefix_string)) {
     LOG(ERROR) << "Error parsing path prefix";
@@ -302,7 +302,7 @@
 
   // Recover the path by appending the suffix to the prefix.
   current_byte = structure_beginning + path_suffix_offset;
-  base::string16 suffix_string;
+  std::wstring suffix_string;
 
   if (!NullTerminatedStringToString16(file_buffer, is_unicode, &current_byte,
                                       &suffix_string)) {
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.h b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.h
index 6140980..6e69f56 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.h
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 
-#include "base/strings/string16.h"
 #include "base/win/scoped_handle.h"
 #include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h"
 
@@ -69,9 +68,9 @@
 }  // namespace internal
 
 struct ParsedLnkFile {
-  base::string16 target_path;
-  base::string16 command_line_arguments;
-  base::string16 icon_location;
+  std::wstring target_path;
+  std::wstring command_line_arguments;
+  std::wstring icon_location;
 };
 
 mojom::LnkParsingResult ParseLnk(base::win::ScopedHandle file_handle,
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_fuzzer.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_fuzzer.cc
index 244c4415..825542d 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_fuzzer.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_fuzzer.cc
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 
 #include "chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser.h"
diff --git a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_unittest.cc b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_unittest.cc
index 0c6f411..d19c0a5 100644
--- a/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_unittest.cc
+++ b/chrome/chrome_cleaner/parsers/shortcut_parser/target/lnk_parser_unittest.cc
@@ -85,7 +85,7 @@
 
   void CheckParsedShortcut(ParsedLnkFile* parsed_shortcut,
                            base::FilePath target_path,
-                           base::string16 arguments,
+                           std::wstring arguments,
                            base::FilePath icon_location) {
     base::FilePath parsed_file_path(parsed_shortcut->target_path);
     ASSERT_TRUE(PathEqual(parsed_file_path, target_path));
@@ -97,7 +97,7 @@
   }
 
   bool CreateFileWithUTF16Name(base::FilePath* file_path) {
-    base::string16 UTF16_file_name = L"NormalFile\x0278";
+    std::wstring UTF16_file_name = L"NormalFile\x0278";
     *file_path = temp_dir_.GetPath().Append(UTF16_file_name);
     return CreateFileInFolder(temp_dir_.GetPath(), UTF16_file_name);
   }
@@ -241,7 +241,7 @@
   // https://msdn.microsoft.com/en-us/library/dd871305.aspx for more
   // information.
   bool FindStringDataInBuffer(const std::vector<BYTE>& buffer,
-                              const base::string16& expected_string,
+                              const std::wstring& expected_string,
                               DWORD* found_location) {
     size_t length = expected_string.length();
     if (buffer.size() < length + 2)
@@ -254,7 +254,7 @@
       if (buffer[i] == size_lower && buffer[i + 1] == size_upper) {
         const wchar_t* string_ptr =
             reinterpret_cast<const wchar_t*>(buffer.data() + i + 2);
-        base::string16 found_string(string_ptr, length);
+        std::wstring found_string(string_ptr, length);
         if (found_string == expected_string) {
           found = true;
           *found_location = i;
@@ -320,7 +320,7 @@
 TEST_F(LnkParserTest, ParseLnkWithArgumentsTest) {
   base::win::ShortcutProperties properties;
   properties.set_target(target_file_path_);
-  const base::string16 kArguments = L"Seven";
+  const std::wstring kArguments = L"Seven";
   properties.set_arguments(kArguments.c_str());
 
   base::win::ScopedHandle lnk_handle = CreateAndOpenShortcut(properties);
@@ -336,7 +336,7 @@
 TEST_F(LnkParserTest, ParseLnkWithExtraStringStructures) {
   base::win::ShortcutProperties properties;
   properties.set_target(target_file_path_);
-  const base::string16 kArguments =
+  const std::wstring kArguments =
       L"lavidaesbella --arg1 --argmento2 --argumento3 /a --Seven";
   properties.set_arguments(kArguments.c_str());
 
@@ -435,7 +435,7 @@
   base::win::ShortcutProperties properties;
   properties.set_target(target_file_path_);
   properties.set_working_dir(temp_dir_.GetPath());
-  const base::string16 kArguments = L"foo --bar";
+  const std::wstring kArguments = L"foo --bar";
   properties.set_arguments(kArguments.c_str());
 
   // Create a LNK file which thinks its arguments are much longer than they
@@ -450,7 +450,7 @@
 }
 
 TEST_F(LnkParserTest, ArgumentsSizeCorruptedShortcutTest_ZeroSize) {
-  const base::string16 kArguments = L"foo --bar";
+  const std::wstring kArguments = L"foo --bar";
 
   base::win::ShortcutProperties properties;
   properties.set_target(target_file_path_);
@@ -468,7 +468,7 @@
 }
 
 TEST_F(LnkParserTest, ArgumentsSizeCorruptedShortcutTest_NegativeSize) {
-  const base::string16 kArguments = L"foo --bar";
+  const std::wstring kArguments = L"foo --bar";
 
   base::win::ShortcutProperties properties;
   properties.set_target(target_file_path_);
@@ -488,7 +488,7 @@
 }
 
 TEST_F(LnkParserTest, ArgumentsSizeCorruptedShortcutTest_Smaller) {
-  const base::string16 kArguments = L"foo --bar";
+  const std::wstring kArguments = L"foo --bar";
 
   base::win::ShortcutProperties properties;
   properties.set_target(target_file_path_);
diff --git a/chrome/chrome_cleaner/parsers/target/parser_impl.cc b/chrome/chrome_cleaner/parsers/target/parser_impl.cc
index 1cf6de6..1cd4bced 100644
--- a/chrome/chrome_cleaner/parsers/target/parser_impl.cc
+++ b/chrome/chrome_cleaner/parsers/target/parser_impl.cc
@@ -42,9 +42,9 @@
   if (!shortcut_handle.IsValid()) {
     LOG(ERROR) << "Unable to get raw file HANDLE from mojo.";
     std::move(callback).Run(mojom::LnkParsingResult::INVALID_HANDLE,
-                            base::make_optional<base::string16>(),
-                            base::make_optional<base::string16>(),
-                            base::make_optional<base::string16>());
+                            base::make_optional<std::wstring>(),
+                            base::make_optional<std::wstring>(),
+                            base::make_optional<std::wstring>());
     return;
   }
 
@@ -54,17 +54,16 @@
 
   if (result != mojom::LnkParsingResult::SUCCESS) {
     LOG(ERROR) << "Error parsing the shortcut";
-    std::move(callback).Run(result, base::make_optional<base::string16>(),
-                            base::make_optional<base::string16>(),
-                            base::make_optional<base::string16>());
+    std::move(callback).Run(result, base::make_optional<std::wstring>(),
+                            base::make_optional<std::wstring>(),
+                            base::make_optional<std::wstring>());
     return;
   }
 
   std::move(callback).Run(
-      result, base::make_optional<base::string16>(parsed_shortcut.target_path),
-      base::make_optional<base::string16>(
-          parsed_shortcut.command_line_arguments),
-      base::make_optional<base::string16>(parsed_shortcut.icon_location));
+      result, base::make_optional<std::wstring>(parsed_shortcut.target_path),
+      base::make_optional<std::wstring>(parsed_shortcut.command_line_arguments),
+      base::make_optional<std::wstring>(parsed_shortcut.icon_location));
 }
 
 }  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc b/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc
index fda63a0..00b4366 100644
--- a/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc
+++ b/chrome/chrome_cleaner/parsers/target/parser_impl_unittest.cc
@@ -129,7 +129,7 @@
   base::win::ShortcutProperties shortcut_properties;
   shortcut_properties.set_target(not_lnk_file_path_);
   shortcut_properties.set_icon(not_lnk_file_path_, /*icon_index=*/0);
-  const base::string16 lnk_arguments = L"argument1 -f -t -a -o";
+  const std::wstring lnk_arguments = L"argument1 -f -t -a -o";
   shortcut_properties.set_arguments(lnk_arguments);
 
   base::win::ScopedHandle lnk_file_handle = CreateAndOpenShortcutInTempDir(
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index b5d8fb4a..48911a7 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -39,6 +39,7 @@
 #include "chrome/common/render_messages.h"
 #include "chrome/common/secure_origin_allowlist.h"
 #include "chrome/common/url_constants.h"
+#include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/renderer_resources.h"
@@ -1665,8 +1666,52 @@
 }
 
 bool ChromeContentRendererClient::RequiresWebComponentsV0(const GURL& url) {
+  if (url.SchemeIs(content::kChromeUIScheme)) {
+    base::StringPiece host_piece = url.host_piece();
+    // TODO(crbug.com/1014322): Remove when migrated to Polymer3.
+    return host_piece == chrome::kChromeUIMdUserManagerHost ||
+           host_piece == content::kChromeUIResourcesHost ||
+           // TODO(crbug.com/1006778): Remove when chrome://tracing is fully
+           // removed.
+           host_piece == content::kChromeUITracingHost ||
+           // TODO(crbug.com/1110954): Remove when migrated away from HTML
+           // imports.
+           host_piece == chrome::kChromeUIBluetoothInternalsHost ||
+#if defined(OS_CHROMEOS)
+           // TODO(crbug.com/1111430): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIAccountManagerErrorHost ||
+           host_piece == chrome::kChromeUIAccountManagerWelcomeHost ||
+           host_piece == chrome::kChromeUIAccountMigrationWelcomeHost ||
+           // TODO(crbug.com/1111430): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIAddSupervisionHost ||
+           // TODO(crbug.com/1111849): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIAssistantOptInHost ||
+           // TODO(crbug.com/1111477): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUICellularSetupHost ||
+           // TODO(crbug.com/1090884): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIInternetConfigDialogHost ||
+           // TODO(crbug.com/1090883): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIInternetDetailDialogHost ||
+           // TODO(crbug.com/1022196): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIMultiDeviceSetupHost ||
+           // TODO(crbug.com/1111852): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUINetworkHost ||
+           // TODO(crbug.com/1111387): Remove when migrated away from HTML
+           // Imports.
+           host_piece == chrome::kChromeUIOobeHost ||
+           // TODO(crbug.com/1045266): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIOSSettingsHost ||
+           // TODO(crbug.com/1022192): Remove when migrated to Polymer3.
+           host_piece == chrome::kChromeUIPasswordChangeHost ||
+           // TODO(crbug.com/1111393): Remove when migrated away from HTML
+           // imports.
+           host_piece == "file_manager_test" ||
+#endif
+           false;
+  }
+
   // TODO(1025782): For now, file:// URLs are allowed to access Web Components
   // v0 features. This will be removed once origin trials support file:// URLs
   // for this purpose.
-  return url.SchemeIs(content::kChromeUIScheme) || url.SchemeIs("file");
+  return url.SchemeIs("file");
 }
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 8e7241d..17d61d2d 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -27,8 +27,6 @@
 #include "chrome/browser/background_fetch/background_fetch_delegate_factory.h"
 #include "chrome/browser/background_fetch/background_fetch_delegate_impl.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/bookmarks/chrome_bookmark_client.h"
-#include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
@@ -36,7 +34,6 @@
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/chrome_history_client.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/web_history_service_factory.h"
@@ -55,7 +52,6 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/ssl/stateful_ssl_host_state_delegate_factory.h"
-#include "chrome/browser/sync/bookmark_sync_service_factory.h"
 #include "chrome/browser/transition_manager/full_browser_transition_manager.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
 #include "chrome/browser/web_data_service_factory.h"
@@ -69,10 +65,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_profile_validator.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/bookmarks/common/bookmark_constants.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/favicon/core/favicon_service.h"
 #include "components/history/content/browser/content_visit_delegate.h"
 #include "components/history/content/browser/history_database_helper.h"
 #include "components/history/core/browser/history_backend.h"
@@ -85,7 +78,6 @@
 #include "components/keyed_service/core/simple_dependency_manager.h"
 #include "components/keyed_service/core/simple_factory_key.h"
 #include "components/keyed_service/core/simple_key_map.h"
-#include "components/offline_pages/buildflags/buildflags.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/omnibox/browser/history_index_restore_observer.h"
 #include "components/omnibox/browser/in_memory_url_index.h"
@@ -156,13 +148,7 @@
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
 #endif
 
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-#include "chrome/browser/offline_pages/offline_page_model_factory.h"
-#include "components/offline_pages/core/stub_offline_page_model.h"
-#endif
-
 using base::Time;
-using bookmarks::BookmarkModel;
 using content::BrowserThread;
 using content::DownloadManagerDelegate;
 using testing::NiceMock;
@@ -194,17 +180,6 @@
   return std::move(in_memory_url_index);
 }
 
-std::unique_ptr<KeyedService> BuildBookmarkModel(
-    content::BrowserContext* context) {
-  Profile* profile = Profile::FromBrowserContext(context);
-  std::unique_ptr<BookmarkModel> bookmark_model(
-      new BookmarkModel(std::make_unique<ChromeBookmarkClient>(
-          profile, ManagedBookmarkServiceFactory::GetForProfile(profile),
-          BookmarkSyncServiceFactory::GetForProfile(profile))));
-  bookmark_model->Load(profile->GetPrefs(), profile->GetPath());
-  return std::move(bookmark_model);
-}
-
 void TestProfileErrorCallback(WebDataServiceWrapper::ErrorType error_type,
                               sql::InitStatus status,
                               const std::string& diagnostics) {
@@ -220,12 +195,6 @@
       base::BindRepeating(&TestProfileErrorCallback));
 }
 
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-std::unique_ptr<KeyedService> BuildOfflinePageModel(SimpleFactoryKey* key) {
-  return std::make_unique<offline_pages::StubOfflinePageModel>();
-}
-#endif
-
 std::unique_ptr<KeyedService> BuildPersonalDataManagerInstanceFor(
     content::BrowserContext* context) {
   return std::unique_ptr<KeyedService>(
@@ -601,12 +570,6 @@
   ignore_result(temp_dir_.Delete());
 }
 
-void TestingProfile::CreateFaviconService() {
-  // It is up to the caller to create the history service if one is needed.
-  FaviconServiceFactory::GetInstance()->SetTestingFactory(
-      this, FaviconServiceFactory::GetDefaultFactory());
-}
-
 bool TestingProfile::CreateHistoryService(bool delete_file, bool no_db) {
   // Should never be created multiple times.
   DCHECK(!HistoryServiceFactory::GetForProfileWithoutCreating(this));
@@ -638,22 +601,6 @@
   return true;
 }
 
-void TestingProfile::CreateBookmarkModel(bool delete_file) {
-  if (delete_file) {
-    base::FilePath path = GetPath().Append(bookmarks::kBookmarksFileName);
-    base::DeleteFile(path);
-  }
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  offline_pages::OfflinePageModelFactory::GetInstance()->SetTestingFactory(
-      GetProfileKey(), base::BindRepeating(&BuildOfflinePageModel));
-#endif
-  ManagedBookmarkServiceFactory::GetInstance()->SetTestingFactory(
-      this, ManagedBookmarkServiceFactory::GetDefaultFactory());
-  // This creates the BookmarkModel.
-  ignore_result(BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse(
-      this, base::BindRepeating(&BuildBookmarkModel)));
-}
-
 void TestingProfile::CreateWebDataService() {
   WebDataServiceFactory::GetInstance()->SetTestingFactory(
       this, base::BindRepeating(&BuildWebDataService));
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 6a1b333..135017b 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -220,10 +220,6 @@
 
   ~TestingProfile() override;
 
-  // Creates the favicon service. Consequent calls would recreate the service.
-  // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
-  void CreateFaviconService();
-
   // !!!!!!!! WARNING: THIS IS GENERALLY NOT SAFE TO CALL! !!!!!!!!
   // This bypasses the BrowserContextDependencyManager, and in particular, it
   // destroys any previously-created HistoryService. That means any other
@@ -240,20 +236,6 @@
   // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
   bool CreateHistoryService(bool delete_file, bool no_db) WARN_UNUSED_RESULT;
 
-  // Creates the BookmarkBarModel. If not invoked the bookmark bar model is
-  // NULL. If |delete_file| is true, the bookmarks file is deleted first, then
-  // the model is created. As TestingProfile deletes the directory containing
-  // the files used by HistoryService, the boolean only matters if you're
-  // recreating the BookmarkModel.
-  //
-  // NOTE: this does not block until the bookmarks are loaded. For that use
-  // WaitForBookmarkModelToLoad().
-  //
-  // DEPRECATED: Use Builder::AddTestingProfile() together with
-  // BookmarkModelFactory::GetDefaultFactory() in new code.
-  // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
-  void CreateBookmarkModel(bool delete_file);
-
   // Creates a WebDataService. If not invoked, the web data service is NULL.
   // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
   void CreateWebDataService();
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index d276c99..03dda4d 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -439,6 +439,7 @@
   base::ScopedFD devnull;
   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (!cmd_line->HasSwitch("verbose") &&
+      !cmd_line->HasSwitch("enable-chrome-logs") &&
       cmd_line->GetSwitchValueASCII("log-level") != "ALL") {
     // Redirect stderr to /dev/null, so that Chrome log spew doesn't confuse
     // users.
diff --git a/chrome/test/chromedriver/server/chromedriver_server.cc b/chrome/test/chromedriver/server/chromedriver_server.cc
index 81a4b3c..8e1a82f 100644
--- a/chrome/test/chromedriver/server/chromedriver_server.cc
+++ b/chrome/test/chromedriver/server/chromedriver_server.cc
@@ -532,6 +532,8 @@
             "base URL path prefix for commands, e.g. wd/url",
         "readable-timestamp",
             "add readable timestamps to log",
+        "enable-chrome-logs",
+            "show logs from the browser (overrides other logging options)"
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
         "disable-dev-shm-usage",
             "do not use /dev/shm "
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index e159f4e..9f646bb 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -154,7 +154,7 @@
  */
 function editDialogPartsAreShownCorrectly(passwordDialog) {
   assertEquals(
-      passwordDialog.i18n('editCompromisedPasswordTitle'),
+      passwordDialog.i18n('editPasswordTitle'),
       passwordDialog.$.title.textContent.trim());
   assertFalse(passwordDialog.$.passwordInput.readonly);
   assertTrue(passwordDialog.$.passwordInput.required);
@@ -654,7 +654,7 @@
     getFirstPasswordListItem(passwordsSection).$.moreActionsButton.click();
     flush();
     assertEquals(
-        passwordsSection.i18n('editCompromisedPassword'),
+        passwordsSection.i18n('editPassword'),
         passwordsSection.$.passwordsListHandler.$$('#menuEditPassword')
             .textContent.trim());
   });
diff --git a/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn b/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn
index 45365a5..4287dccc 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn
+++ b/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn
@@ -145,6 +145,7 @@
 
 js_library("util") {
   deps = [
+    ":error",
     ":state",
     ":tooltip",
     ":type",
diff --git a/chromeos/components/camera_app_ui/resources/src/js/error.js b/chromeos/components/camera_app_ui/resources/src/js/error.js
index 649e977..e4414e2 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/error.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/error.js
@@ -10,6 +10,7 @@
  * @enum {string}
  */
 export const ErrorType = {
+  BROKEN_THUMBNAIL: 'broken-thumbnail',
   UNCAUGHT_PROMISE: 'uncaught-promise',
 };
 
@@ -156,6 +157,14 @@
  * @param {!Error} error
  */
 export function reportError(type, level, error) {
+  // uncaught promise is already logged in console
+  if (type !== ErrorType.UNCAUGHT_PROMISE) {
+    if (level === ErrorLevel.ERROR) {
+      console.error(type, error);
+    } else {
+      console.warn(type, error);
+    }
+  }
   const time = Date.now();
   const frames = getStackFrames(error);
   const errorName = error.name;
diff --git a/chromeos/components/camera_app_ui/resources/src/js/util.js b/chromeos/components/camera_app_ui/resources/src/js/util.js
index 95597d0..6bcd7ab 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/util.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/util.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {browserProxy} from './browser_proxy/browser_proxy.js';
+import {ErrorLevel, ErrorType, reportError} from './error.js';
 import * as state from './state.js';
 import * as tooltip from './tooltip.js';
 import {Facing} from './type.js';
@@ -335,37 +336,48 @@
  *     ratio of input picture.
  * @return {!Promise<!Blob>} Promise for the result.
  */
-export function scalePicture(url, isVideo, width, height = undefined) {
+export async function scalePicture(url, isVideo, width, height = undefined) {
   const element = document.createElement(isVideo ? 'video' : 'img');
   if (isVideo) {
     element.preload = 'auto';
   }
+  await new Promise((resolve, reject) => {
+    element.addEventListener(isVideo ? 'canplay' : 'load', resolve);
+    element.addEventListener('error', reject);
+    element.src = url;
+  });
+  const canvas = document.createElement('canvas');
+  const context = canvas.getContext('2d');
+  if (height === undefined) {
+    const ratio = isVideo ? element.videoHeight / element.videoWidth :
+                            element.height / element.width;
+    height = Math.round(width * ratio);
+  }
+  canvas.width = width;
+  canvas.height = height;
+  context.drawImage(element, 0, 0, width, height);
+
+  /**
+   * @type {Uint8ClampedArray} A one-dimensional pixels array in RGBA order.
+   */
+  const data = context.getImageData(0, 0, width, height).data;
+  if (data.every((byte) => byte === 0)) {
+    reportError(
+        ErrorType.BROKEN_THUMBNAIL, ErrorLevel.ERROR,
+        new Error('The thumbnail content is broken.'));
+    // Do not throw an error here. A black thumbnail is still better than no
+    // thumbnail to let user open the corresponding picutre in gallery.
+  }
+
   return new Promise((resolve, reject) => {
-           element.addEventListener(isVideo ? 'canplay' : 'load', resolve);
-           element.addEventListener('error', reject);
-           element.src = url;
-         })
-      .then(() => {
-        const canvas = document.createElement('canvas');
-        const context = canvas.getContext('2d');
-        if (height === undefined) {
-          const ratio = isVideo ? element.videoHeight / element.videoWidth :
-                                  element.height / element.width;
-          height = Math.round(width * ratio);
-        }
-        canvas.width = width;
-        canvas.height = height;
-        context.drawImage(element, 0, 0, width, height);
-        return new Promise((resolve, reject) => {
-          canvas.toBlob((blob) => {
-            if (blob) {
-              resolve(blob);
-            } else {
-              reject(new Error('Failed to create thumbnail.'));
-            }
-          }, 'image/jpeg');
-        });
-      });
+    canvas.toBlob((blob) => {
+      if (blob) {
+        resolve(blob);
+      } else {
+        reject(new Error('Failed to create thumbnail.'));
+      }
+    }, 'image/jpeg');
+  });
 }
 
 /**
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index c8a6133..955a732 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -212,6 +212,7 @@
     "arc_features_parser.h",
     "arc_service_manager.cc",
     "arc_service_manager.h",
+    "session/adb_sideloading_availability_delegate.h",
     "session/arc_bridge_host_impl.cc",
     "session/arc_bridge_host_impl.h",
     "session/arc_bridge_service.cc",
diff --git a/components/arc/session/adb_sideloading_availability_delegate.h b/components/arc/session/adb_sideloading_availability_delegate.h
new file mode 100644
index 0000000..57494f20e
--- /dev/null
+++ b/components/arc/session/adb_sideloading_availability_delegate.h
@@ -0,0 +1,27 @@
+// 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 COMPONENTS_ARC_SESSION_ADB_SIDELOADING_AVAILABILITY_DELEGATE_H_
+#define COMPONENTS_ARC_SESSION_ADB_SIDELOADING_AVAILABILITY_DELEGATE_H_
+
+#include "base/callback_forward.h"
+
+namespace arc {
+
+// An abstract class describing a delegate that can fetch the availability of
+// ADB sideloading. It is used to inject the dependency of the ARC component to
+// ArcSessionManager which extends this abstract class and accesses the
+// sideloading availability status of CrostiniFeatures.
+// TODO(b/161813141): Refactor this to remove the dependency
+class AdbSideloadingAvailabilityDelegate {
+ public:
+  virtual ~AdbSideloadingAvailabilityDelegate() = default;
+
+  // Fetches the ADB sideloading availability value
+  virtual void CanChangeAdbSideloading(
+      base::OnceCallback<void(bool can_change_adb_sideloading)> callback) = 0;
+};
+}  // namespace arc
+
+#endif  // COMPONENTS_ARC_SESSION_ADB_SIDELOADING_AVAILABILITY_DELEGATE_H_
diff --git a/components/arc/session/arc_container_client_adapter.cc b/components/arc/session/arc_container_client_adapter.cc
index 482f770..d331e396 100644
--- a/components/arc/session/arc_container_client_adapter.cc
+++ b/components/arc/session/arc_container_client_adapter.cc
@@ -110,6 +110,8 @@
     login_manager::UpgradeArcContainerRequest request;
     request.set_account_id(params.account_id);
     request.set_is_account_managed(params.is_account_managed);
+    request.set_is_managed_adb_sideloading_allowed(
+        params.is_managed_adb_sideloading_allowed);
     request.set_skip_boot_completed_broadcast(
         params.skip_boot_completed_broadcast);
     request.set_packages_cache_mode(
diff --git a/components/arc/session/arc_session.cc b/components/arc/session/arc_session.cc
index a129f13..7969f8d 100644
--- a/components/arc/session/arc_session.cc
+++ b/components/arc/session/arc_session.cc
@@ -25,10 +25,11 @@
     ash::DefaultScaleFactorRetriever* retriever,
     version_info::Channel channel,
     chromeos::SchedulerConfigurationManagerBase*
-        scheduler_configuration_manager) {
+        scheduler_configuration_manager,
+    AdbSideloadingAvailabilityDelegate* adb_sideloading_availability_delegate) {
   return std::make_unique<ArcSessionImpl>(
       ArcSessionImpl::CreateDelegate(arc_bridge_service, retriever, channel),
-      scheduler_configuration_manager);
+      scheduler_configuration_manager, adb_sideloading_availability_delegate);
 }
 
 }  // namespace arc
diff --git a/components/arc/session/arc_session.h b/components/arc/session/arc_session.h
index 4fe0d48..0fdfa12 100644
--- a/components/arc/session/arc_session.h
+++ b/components/arc/session/arc_session.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
+#include "components/arc/session/adb_sideloading_availability_delegate.h"
 #include "components/arc/session/arc_stop_reason.h"
 #include "components/arc/session/arc_upgrade_params.h"
 
@@ -62,7 +63,10 @@
       ash::DefaultScaleFactorRetriever* retriever,
       version_info::Channel channel,
       chromeos::SchedulerConfigurationManagerBase*
-          scheduler_configuration_manager);
+          scheduler_configuration_manager,
+      AdbSideloadingAvailabilityDelegate*
+          adb_sideloading_availability_delegate);
+
   virtual ~ArcSession();
 
   // Sends D-Bus message to start a mini-container.
diff --git a/components/arc/session/arc_session_impl.cc b/components/arc/session/arc_session_impl.cc
index d782afd2..0ecd7b7 100644
--- a/components/arc/session/arc_session_impl.cc
+++ b/components/arc/session/arc_session_impl.cc
@@ -323,12 +323,16 @@
                                                   channel);
 }
 
-ArcSessionImpl::ArcSessionImpl(std::unique_ptr<Delegate> delegate,
-                               chromeos::SchedulerConfigurationManagerBase*
-                                   scheduler_configuration_manager)
+ArcSessionImpl::ArcSessionImpl(
+    std::unique_ptr<Delegate> delegate,
+    chromeos::SchedulerConfigurationManagerBase*
+        scheduler_configuration_manager,
+    AdbSideloadingAvailabilityDelegate* adb_sideloading_availability_delegate)
     : delegate_(std::move(delegate)),
       client_(delegate_->CreateClient()),
-      scheduler_configuration_manager_(scheduler_configuration_manager) {
+      scheduler_configuration_manager_(scheduler_configuration_manager),
+      adb_sideloading_availability_delegate_(
+          adb_sideloading_availability_delegate) {
   DCHECK(client_);
   client_->AddObserver(this);
 }
@@ -495,6 +499,16 @@
     return;
   }
 
+  adb_sideloading_availability_delegate_->CanChangeAdbSideloading(
+      base::BindOnce(&ArcSessionImpl::OnCanChangeAdbSideloading,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void ArcSessionImpl::OnCanChangeAdbSideloading(
+    bool can_change_adb_sideloading) {
+  upgrade_params_.is_managed_adb_sideloading_allowed =
+      can_change_adb_sideloading;
+
   delegate_->CreateSocket(base::BindOnce(&ArcSessionImpl::OnSocketCreated,
                                          weak_factory_.GetWeakPtr()));
 }
diff --git a/components/arc/session/arc_session_impl.h b/components/arc/session/arc_session_impl.h
index 21366e4..b49e8f6 100644
--- a/components/arc/session/arc_session_impl.h
+++ b/components/arc/session/arc_session_impl.h
@@ -162,7 +162,7 @@
     using GetLcdDensityCallback = base::OnceCallback<void(int32_t)>;
 
     // Gets the lcd density via callback. The callback may be invoked
-    // immediately if its already available, or called asynchronosly later if
+    // immediately if it's already available, or called asynchronously later if
     // it's not yet available. Calling this method while there is a pending
     // callback will cancel the pending callback.
     virtual void GetLcdDensity(GetLcdDensityCallback callback) = 0;
@@ -180,7 +180,9 @@
 
   ArcSessionImpl(std::unique_ptr<Delegate> delegate,
                  chromeos::SchedulerConfigurationManagerBase*
-                     scheduler_configuration_manager);
+                     scheduler_configuration_manager,
+                 AdbSideloadingAvailabilityDelegate*
+                     adb_sideloading_availability_delegate);
   ~ArcSessionImpl() override;
 
   // Returns default delegate implementation used for the production.
@@ -248,6 +250,9 @@
   // Free disk space under /home in bytes.
   void OnFreeDiskSpace(int64_t space);
 
+  // Whether adb sideloading can be changed
+  void OnCanChangeAdbSideloading(bool can_change_adb_sideloading);
+
   // Checks whether a function runs on the thread where the instance is
   // created.
   THREAD_CHECKER(thread_checker_);
@@ -284,6 +289,10 @@
   chromeos::SchedulerConfigurationManagerBase* const
       scheduler_configuration_manager_;
 
+  // Owned by ArcSessionManager.
+  AdbSideloadingAvailabilityDelegate* const
+      adb_sideloading_availability_delegate_;
+
   // WeakPtrFactory to use callbacks.
   base::WeakPtrFactory<ArcSessionImpl> weak_factory_{this};
 
diff --git a/components/arc/session/arc_session_impl_unittest.cc b/components/arc/session/arc_session_impl_unittest.cc
index 76f1d1e8..a61cecf 100644
--- a/components/arc/session/arc_session_impl_unittest.cc
+++ b/components/arc/session/arc_session_impl_unittest.cc
@@ -278,6 +278,26 @@
   DISALLOW_COPY_AND_ASSIGN(FakeSchedulerConfigurationManager);
 };
 
+class FakeAdbSideloadingAvailabilityDelegate
+    : public AdbSideloadingAvailabilityDelegate {
+ public:
+  FakeAdbSideloadingAvailabilityDelegate() = default;
+  ~FakeAdbSideloadingAvailabilityDelegate() override = default;
+
+  void CanChangeAdbSideloading(
+      base::OnceCallback<void(bool can_change_adb_sideloading)> callback)
+      override {
+    std::move(callback).Run(can_change_adb_sideloading_);
+  }
+
+  void SetCanChangeAdbSideloading(bool can_change) {
+    can_change_adb_sideloading_ = can_change;
+  }
+
+ private:
+  bool can_change_adb_sideloading_ = false;
+};
+
 class ArcSessionImplTest : public testing::Test {
  public:
   ArcSessionImplTest() = default;
@@ -315,6 +335,10 @@
 
   FakeSchedulerConfigurationManager fake_schedule_configuration_manager_;
 
+  std::unique_ptr<FakeAdbSideloadingAvailabilityDelegate>
+      adb_sideloading_availability_delegate_ =
+          std::make_unique<FakeAdbSideloadingAvailabilityDelegate>();
+
  private:
   std::unique_ptr<ArcSessionImpl, ArcSessionDeleter> CreateArcSessionInternal(
       std::unique_ptr<ArcSessionImpl::Delegate> delegate,
@@ -323,7 +347,8 @@
       delegate = std::make_unique<FakeDelegate>(lcd_density);
     return std::unique_ptr<ArcSessionImpl, ArcSessionDeleter>(
         new ArcSessionImpl(std::move(delegate),
-                           &fake_schedule_configuration_manager_));
+                           &fake_schedule_configuration_manager_,
+                           adb_sideloading_availability_delegate_.get()));
   }
 
   base::test::TaskEnvironment task_environment_;
@@ -872,5 +897,33 @@
   EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting());
 }
 
+// Test that correct value false for managed sideloading is passed
+TEST_F(ArcSessionImplTest, CanChangeAdbSideloading_False) {
+  auto arc_session = CreateArcSession();
+  adb_sideloading_availability_delegate_->SetCanChangeAdbSideloading(false);
+
+  arc_session->StartMiniInstance();
+  arc_session->RequestUpgrade(DefaultUpgradeParams());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(GetClient(arc_session.get())
+                   ->last_upgrade_params()
+                   .is_managed_adb_sideloading_allowed);
+}
+
+// Test that correct value true for managed sideloading is passed
+TEST_F(ArcSessionImplTest, CanChangeAdbSideloading_True) {
+  auto arc_session = CreateArcSession();
+  adb_sideloading_availability_delegate_->SetCanChangeAdbSideloading(true);
+
+  arc_session->StartMiniInstance();
+  arc_session->RequestUpgrade(DefaultUpgradeParams());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(GetClient(arc_session.get())
+                  ->last_upgrade_params()
+                  .is_managed_adb_sideloading_allowed);
+}
+
 }  // namespace
 }  // namespace arc
diff --git a/components/arc/session/arc_upgrade_params.h b/components/arc/session/arc_upgrade_params.h
index cc6cd61..39b7890 100644
--- a/components/arc/session/arc_upgrade_params.h
+++ b/components/arc/session/arc_upgrade_params.h
@@ -48,6 +48,10 @@
   // Whether the account is managed.
   bool is_account_managed;
 
+  // Whether adb sideloading is allowed when the account and/or the device is
+  // managed.
+  bool is_managed_adb_sideloading_allowed = false;
+
   // Option to disable ACTION_BOOT_COMPLETED broadcast for 3rd party apps.
   // The constructor automatically populates this from command-line.
   bool skip_boot_completed_broadcast;
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index dc224cb..b1971df 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -865,7 +865,8 @@
     }
   }
 
-  // TODO(niwa): Handle |is_managed_account| in |upgrade_params| when we
+  // TODO(niwa): Handle |is_account_managed| and
+  // |is_managed_adb_sideloading_allowed| in |upgrade_params| when we
   // implement apk sideloading for ARCVM.
   return result;
 }
diff --git a/components/autofill/core/browser/autofill_profile_sync_util.cc b/components/autofill/core/browser/autofill_profile_sync_util.cc
index ed962b2..ecd93d3 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -13,21 +13,63 @@
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 // TODO(crbug.com/904390): Remove when the investigation is over.
 #include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/geo/country_names.h"
 #include "components/autofill/core/browser/proto/autofill_sync.pb.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/sync/model/entity_data.h"
 
+using autofill::data_util::TruncateUTF8;
 using base::UTF16ToUTF8;
 using base::UTF8ToUTF16;
-using autofill::data_util::TruncateUTF8;
 using sync_pb::AutofillProfileSpecifics;
 using syncer::EntityData;
 
 namespace autofill {
+
+using structured_address::VerificationStatus;
+
 namespace {
 
+//  Converts the verification status representation used in the
+//  AutofillProfileSpecifics to the representation used in AutofillProfile.
+VerificationStatus ConvertSpecificsToProfileVerificationStatus(
+    AutofillProfileSpecifics::VerificationStatus entity_status) {
+  switch (entity_status) {
+    case sync_pb::
+        AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED:
+      return VerificationStatus::kNoStatus;
+    case sync_pb::AutofillProfileSpecifics_VerificationStatus_PARSED:
+      return VerificationStatus::kParsed;
+    case sync_pb::AutofillProfileSpecifics_VerificationStatus_FORMATTED:
+      return VerificationStatus::kFormatted;
+    case sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED:
+      return VerificationStatus::kObserved;
+    case sync_pb::AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED:
+      return VerificationStatus::kUserVerified;
+  }
+}
+
+// Converts the verification status representation used AutofillProfiles to the
+// one used in AutofillProfileSpecifics.
+AutofillProfileSpecifics::VerificationStatus
+ConvertProfileToSpecificsVerificationStatus(VerificationStatus profile_status) {
+  switch (profile_status) {
+    case (VerificationStatus::kNoStatus):
+      return sync_pb::
+          AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED;
+    case (VerificationStatus::kParsed):
+      return sync_pb::AutofillProfileSpecifics_VerificationStatus_PARSED;
+    case (VerificationStatus::kFormatted):
+      return sync_pb::AutofillProfileSpecifics_VerificationStatus_FORMATTED;
+    case (VerificationStatus::kObserved):
+      return sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED;
+    case (VerificationStatus::kUserVerified):
+      return sync_pb::AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED;
+  }
+}
+
 bool IsAutofillProfileSpecificsValid(
     const AutofillProfileSpecifics& specifics) {
   return base::IsValidGUID(specifics.guid());
@@ -58,14 +100,44 @@
       entry.is_client_validity_states_updated());
 
   // Set repeated fields.
+  specifics->add_name_honorific(
+      TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_HONORIFIC_PREFIX))));
   specifics->add_name_first(
       TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_FIRST))));
   specifics->add_name_middle(
       TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_MIDDLE))));
   specifics->add_name_last(
       TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_LAST))));
+  specifics->add_name_last_first(
+      TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_LAST_FIRST))));
+  specifics->add_name_last_second(
+      TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_LAST_SECOND))));
+  specifics->add_name_last_conjunction(
+      TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_LAST_CONJUNCTION))));
   specifics->add_name_full(
       TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_FULL))));
+
+  specifics->add_name_honorific_status(
+      ConvertProfileToSpecificsVerificationStatus(
+          entry.GetVerificationStatus(NAME_HONORIFIC_PREFIX)));
+  specifics->add_name_first_status(ConvertProfileToSpecificsVerificationStatus(
+      entry.GetVerificationStatus(NAME_FIRST)));
+  specifics->add_name_middle_status(ConvertProfileToSpecificsVerificationStatus(
+      entry.GetVerificationStatus(NAME_MIDDLE)));
+  specifics->add_name_last_status(ConvertProfileToSpecificsVerificationStatus(
+      entry.GetVerificationStatus(NAME_LAST)));
+  specifics->add_name_last_first_status(
+      ConvertProfileToSpecificsVerificationStatus(
+          entry.GetVerificationStatus(NAME_LAST_FIRST)));
+  specifics->add_name_last_conjunction_status(
+      ConvertProfileToSpecificsVerificationStatus(
+          entry.GetVerificationStatus(NAME_LAST_CONJUNCTION)));
+  specifics->add_name_last_second_status(
+      ConvertProfileToSpecificsVerificationStatus(
+          entry.GetVerificationStatus(NAME_LAST_SECOND)));
+  specifics->add_name_full_status(ConvertProfileToSpecificsVerificationStatus(
+      entry.GetVerificationStatus(NAME_FULL)));
+
   specifics->add_email_address(
       TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(EMAIL_ADDRESS))));
   specifics->add_phone_home_whole_number(
@@ -113,15 +185,91 @@
       specifics.validity_state_bitfield());
 
   // Set repeated fields.
-  profile->SetRawInfo(NAME_FIRST, UTF8ToUTF16(specifics.name_first_size()
-                                                  ? specifics.name_first(0)
-                                                  : std::string()));
-  profile->SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(specifics.name_middle_size()
-                                                   ? specifics.name_middle(0)
-                                                   : std::string()));
-  profile->SetRawInfo(
-      NAME_LAST, UTF8ToUTF16(specifics.name_last_size() ? specifics.name_last(0)
-                                                        : std::string()));
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_HONORIFIC_PREFIX,
+      UTF8ToUTF16(specifics.name_honorific_size() ? specifics.name_honorific(0)
+                                                  : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_honorific_status_size()
+              ? specifics.name_honorific_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_FIRST,
+      UTF8ToUTF16(specifics.name_first_size() ? specifics.name_first(0)
+                                              : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_first_status_size()
+              ? specifics.name_first_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_MIDDLE,
+      UTF8ToUTF16(specifics.name_middle_size() ? specifics.name_middle(0)
+                                               : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_middle_status_size()
+              ? specifics.name_middle_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_LAST,
+      UTF8ToUTF16(specifics.name_last_size() ? specifics.name_last(0)
+                                             : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_last_status_size()
+              ? specifics.name_last_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_LAST_FIRST,
+      UTF8ToUTF16(specifics.name_last_first_size()
+                      ? specifics.name_last_first(0)
+                      : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_last_first_status_size()
+              ? specifics.name_last_first_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_LAST_CONJUNCTION,
+      UTF8ToUTF16(specifics.name_last_conjunction_size()
+                      ? specifics.name_last_conjunction(0)
+                      : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_last_conjunction_status_size()
+              ? specifics.name_last_conjunction_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  profile->SetRawInfoWithVerificationStatus(
+      NAME_LAST_SECOND,
+      UTF8ToUTF16(specifics.name_last_second_size()
+                      ? specifics.name_last_second(0)
+                      : std::string()),
+      ConvertSpecificsToProfileVerificationStatus(
+          specifics.name_last_second_status_size()
+              ? specifics.name_last_second_status(0)
+              : AutofillProfileSpecifics::VerificationStatus::
+                    AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+
+  // Older versions don't have a separate full name; don't overwrite full name
+  // in this case.
+  if (specifics.name_full_size() > 0) {
+    profile->SetRawInfoWithVerificationStatus(
+        NAME_FULL, UTF8ToUTF16(specifics.name_full(0)),
+        ConvertSpecificsToProfileVerificationStatus(
+            specifics.name_full_status_size()
+                ? specifics.name_full_status(0)
+                : AutofillProfileSpecifics::VerificationStatus::
+                      AutofillProfileSpecifics_VerificationStatus_VERIFICATION_STATUS_UNSPECIFIED));
+  }
+
   profile->SetRawInfo(
       EMAIL_ADDRESS,
       UTF8ToUTF16(specifics.email_address_size() ? specifics.email_address(0)
@@ -131,12 +279,6 @@
                                       ? specifics.phone_home_whole_number(0)
                                       : std::string()));
 
-  // Older versions don't have a separate full name; don't overwrite full name
-  // in this case.
-  if (specifics.name_full_size() > 0) {
-    profile->SetRawInfo(NAME_FULL, UTF8ToUTF16(specifics.name_full(0)));
-  }
-
   // Set simple single-valued fields.
   profile->SetRawInfo(COMPANY_NAME, UTF8ToUTF16(specifics.company_name()));
   profile->SetRawInfo(ADDRESS_HOME_CITY,
diff --git a/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc b/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
index 0067781..03a9b30 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
@@ -5,17 +5,21 @@
 #include "components/autofill/core/browser/autofill_profile_sync_util.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
 #include "components/autofill/core/browser/geo/country_names.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/sync/model/entity_data.h"
 #include "components/sync/protocol/sync.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
-
 namespace autofill {
 
+using structured_address::VerificationStatus;
+
 namespace {
 using base::ASCIIToUTF16;
 using base::UTF16ToUTF8;
@@ -38,10 +42,23 @@
   profile.set_use_count(7);
   profile.set_use_date(base::Time::FromTimeT(1423182152));
 
-  profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John K. Doe, Jr."));
-  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
-  profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("K."));
-  profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
+  profile.SetRawInfoWithVerificationStatus(
+      NAME_HONORIFIC_PREFIX, ASCIIToUTF16("Jr."), VerificationStatus::kParsed);
+  profile.SetRawInfoWithVerificationStatus(NAME_FULL,
+                                           ASCIIToUTF16("John K. Doe, Jr."),
+                                           VerificationStatus::kUserVerified);
+  profile.SetRawInfoWithVerificationStatus(NAME_FIRST, ASCIIToUTF16("John"),
+                                           VerificationStatus::kObserved);
+  profile.SetRawInfoWithVerificationStatus(NAME_MIDDLE, ASCIIToUTF16("K."),
+                                           VerificationStatus::kObserved);
+  profile.SetRawInfoWithVerificationStatus(NAME_LAST, ASCIIToUTF16("Doe"),
+                                           VerificationStatus::kFormatted);
+  profile.SetRawInfoWithVerificationStatus(NAME_LAST_FIRST, ASCIIToUTF16("D"),
+                                           VerificationStatus::kParsed);
+  profile.SetRawInfoWithVerificationStatus(NAME_LAST_SECOND, ASCIIToUTF16("e"),
+                                           VerificationStatus::kParsed);
+  profile.SetRawInfoWithVerificationStatus(
+      NAME_LAST_CONJUNCTION, ASCIIToUTF16("o"), VerificationStatus::kParsed);
 
   profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("user@example.com"));
   profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1.800.555.1234"));
@@ -77,11 +94,40 @@
   specifics.set_use_count(7);
   specifics.set_use_date(1423182152);
 
+  specifics.add_name_honorific("Jr.");
   specifics.add_name_first("John");
   specifics.add_name_middle("K.");
   specifics.add_name_last("Doe");
+  specifics.add_name_last_first("D");
+  specifics.add_name_last_second("e");
+  specifics.add_name_last_conjunction("o");
   specifics.add_name_full("John K. Doe, Jr.");
 
+  specifics.add_name_honorific_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_PARSED);
+  specifics.add_name_first_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_OBSERVED);
+  specifics.add_name_middle_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_OBSERVED);
+  specifics.add_name_last_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_FORMATTED);
+  specifics.add_name_last_first_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_PARSED);
+  specifics.add_name_last_second_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_PARSED);
+  specifics.add_name_last_conjunction_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_PARSED);
+  specifics.add_name_full_status(
+      AutofillProfileSpecifics::VerificationStatus::
+          AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED);
+
   specifics.add_email_address("user@example.com");
 
   specifics.add_phone_home_whole_number("1.800.555.1234");
@@ -121,6 +167,10 @@
 // Ensure that all profile fields are able to be synced up from the client to
 // the server.
 TEST_F(AutofillProfileSyncUtilTest, CreateEntityDataFromAutofillProfile) {
+  base::test::ScopedFeatureList structured_names_feature;
+  structured_names_feature.InitAndEnableFeature(
+      features::kAutofillEnableSupportForMoreStructureInNames);
+
   AutofillProfile profile = ConstructCompleteProfile();
   AutofillProfileSpecifics specifics = ConstructCompleteSpecifics();
 
@@ -135,6 +185,10 @@
 
 // Test that fields not set for the input are empty in the output.
 TEST_F(AutofillProfileSyncUtilTest, CreateEntityDataFromAutofillProfile_Empty) {
+  base::test::ScopedFeatureList structured_names_feature;
+  structured_names_feature.InitAndEnableFeature(
+      features::kAutofillEnableSupportForMoreStructureInNames);
+
   AutofillProfile profile(kGuid, std::string());
   ASSERT_FALSE(profile.HasRawInfo(NAME_FULL));
   ASSERT_FALSE(profile.HasRawInfo(COMPANY_NAME));
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index 652fa5c..fd2250e 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -50,6 +50,8 @@
     "actions/navigate_action.h",
     "actions/popup_message_action.cc",
     "actions/popup_message_action.h",
+    "actions/presave_generated_password_action.cc",
+    "actions/presave_generated_password_action.h",
     "actions/prompt_action.cc",
     "actions/prompt_action.h",
     "actions/save_generated_password_action.cc",
@@ -257,6 +259,7 @@
     "actions/fallback_handler/required_fields_fallback_handler_unittest.cc",
     "actions/generate_password_for_form_field_action_unittest.cc",
     "actions/popup_message_action_unittest.cc",
+    "actions/presave_generated_password_action_unittest.cc",
     "actions/prompt_action_unittest.cc",
     "actions/save_generated_password_action_unittest.cc",
     "actions/set_form_field_value_action_unittest.cc",
diff --git a/components/autofill_assistant/browser/actions/action.cc b/components/autofill_assistant/browser/actions/action.cc
index d36fa77b..6b4ce0f 100644
--- a/components/autofill_assistant/browser/actions/action.cc
+++ b/components/autofill_assistant/browser/actions/action.cc
@@ -137,6 +137,9 @@
     case ActionProto::ActionInfoCase::kConfigureUiState:
       out << "ConfigureUiState";
       break;
+    case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
+      out << "PresaveGeneratedPassword";
+      break;
     case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET:
       out << "ACTION_INFO_NOT_SET";
       break;
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index eb9aac5..f47c209 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -404,7 +404,8 @@
   virtual void ClearGenericUi() = 0;
 
   // Sets the OverlayBehavior.
-  virtual void SetOverlayBehavior(ConfigureUiStateProto::OverlayBehavior) = 0;
+  virtual void SetOverlayBehavior(
+      ConfigureUiStateProto::OverlayBehavior overlay_behavior) = 0;
 
  protected:
   ActionDelegate() = default;
diff --git a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc
index 195c6dc..0205448 100644
--- a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc
+++ b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc
@@ -53,12 +53,6 @@
     const autofill::FormFieldData& field_data) {
   if (!status.ok()) {
     EndAction(status);
-  }
-
-  if (!delegate_->GetUserData()->selected_login_.has_value()) {
-    VLOG(1) << "GeneratePasswordForFormFieldAction: requested login details "
-               "not available in client memory.";
-    EndAction(ClientStatus(PRECONDITION_FAILED));
     return;
   }
 
@@ -69,29 +63,20 @@
 
   delegate_->WriteUserData(base::BindOnce(
       &GeneratePasswordForFormFieldAction::StoreGeneratedPasswordToUserData,
-      weak_ptr_factory_.GetWeakPtr(), memory_key, password));
+      weak_ptr_factory_.GetWeakPtr(), memory_key, password, form_data));
 
-  // Presaving stores a generated password with empty username for the cases
-  // when Chrome misses or misclassifies a successful submission. Thus, even if
-  // a site saves/updates the password and Chrome doesn't, the generated
-  // password will be in the password store.
-  // Ideally, a generated password should be presaved after form filling.
-  // Otherwise, if filling fails and submission cannot happen for sure, the
-  // presaved password is pointless.
-  delegate_->GetWebsiteLoginManager()->PresaveGeneratedPassword(
-      *delegate_->GetUserData()->selected_login_, password, form_data,
-      base::BindOnce(&GeneratePasswordForFormFieldAction::EndAction,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     ClientStatus(ACTION_APPLIED)));
+  EndAction(ClientStatus(ACTION_APPLIED));
 }
 
 void GeneratePasswordForFormFieldAction::StoreGeneratedPasswordToUserData(
     const std::string& memory_key,
     const std::string& generated_password,
+    const autofill::FormData& form_data,
     UserData* user_data,
     UserData::FieldChange* field_change) {
   DCHECK(user_data);
   user_data->additional_values_[memory_key] = SimpleValue(generated_password);
+  user_data->password_form_data_ = form_data;
 }
 
 void GeneratePasswordForFormFieldAction::EndAction(const ClientStatus& status) {
diff --git a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.h b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.h
index 0081d4c..680be79 100644
--- a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.h
+++ b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.h
@@ -48,6 +48,7 @@
 
   void StoreGeneratedPasswordToUserData(const std::string& memory_key,
                                         const std::string& generated_password,
+                                        const autofill::FormData& form_data,
                                         UserData* user_data,
                                         UserData::FieldChange* field_change);
 
diff --git a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
index df974c8..4880d7d 100644
--- a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
@@ -60,19 +60,20 @@
 };
 
 TEST_F(GeneratePasswordForFormFieldActionTest, GeneratedPassword) {
+  ON_CALL(mock_action_delegate_, OnRetrieveElementFormAndFieldData)
+      .WillByDefault(RunOnceCallback<1>(ClientStatus(ACTION_APPLIED),
+                                        autofill::FormData(),
+                                        autofill::FormFieldData()));
   GeneratePasswordForFormFieldProto* generate_password_proto =
       proto_.mutable_generate_password_for_form_field();
   *generate_password_proto->mutable_element() =
       Selector({kFakeSelector}).MustBeVisible().proto;
   generate_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
 
-  Selector fake_selector = Selector({kFakeSelector}).MustBeVisible();
-
   GeneratePasswordForFormFieldAction action(&mock_action_delegate_, proto_);
-
-  EXPECT_CALL(mock_website_login_manager_,
-              OnPresaveGeneratedPassword(_, kGeneratedPassword, _, _))
-      .Times(1);
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
 
   action.ProcessAction(callback_.Get());
   EXPECT_EQ(kGeneratedPassword,
@@ -80,4 +81,28 @@
                 .strings()
                 .values(0));
 }
+
+TEST_F(GeneratePasswordForFormFieldActionTest, FormDataIsNotRetrieved) {
+  ON_CALL(mock_action_delegate_, OnRetrieveElementFormAndFieldData)
+      .WillByDefault(RunOnceCallback<1>(ClientStatus(INVALID_SELECTOR),
+                                        autofill::FormData(),
+                                        autofill::FormFieldData()));
+
+  GeneratePasswordForFormFieldProto* generate_password_proto =
+      proto_.mutable_generate_password_for_form_field();
+  *generate_password_proto->mutable_element() =
+      Selector({kFakeSelector}).MustBeVisible().proto;
+
+  GeneratePasswordForFormFieldAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(mock_website_login_manager_, GetGeneratedPassword()).Times(0);
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, INVALID_SELECTOR))));
+
+  action.ProcessAction(callback_.Get());
+
+  EXPECT_FALSE(user_data_.has_additional_value(kMemoryKeyForGeneratedPassword));
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 103d9ba..3ff1c3f 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -112,11 +112,16 @@
                               const autofill::FormData&,
                               const autofill::FormFieldData&)> callback)
       override {
-    autofill::FormData form_data;
-    autofill::FormFieldData field_data;
-    std::move(callback).Run(OkClientStatus(), form_data, field_data);
+    OnRetrieveElementFormAndFieldData(selector, callback);
   }
 
+  MOCK_METHOD2(
+      OnRetrieveElementFormAndFieldData,
+      void(const Selector& selector,
+           base::OnceCallback<void(const ClientStatus&,
+                                   const autofill::FormData&,
+                                   const autofill::FormFieldData&)>& callback));
+
   MOCK_METHOD4(OnFillCardForm,
                void(const autofill::CreditCard* card,
                     const base::string16& cvc,
diff --git a/components/autofill_assistant/browser/actions/presave_generated_password_action.cc b/components/autofill_assistant/browser/actions/presave_generated_password_action.cc
new file mode 100644
index 0000000..af56e7a
--- /dev/null
+++ b/components/autofill_assistant/browser/actions/presave_generated_password_action.cc
@@ -0,0 +1,85 @@
+// 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 "components/autofill_assistant/browser/actions/presave_generated_password_action.h"
+
+#include <utility>
+#include "base/optional.h"
+
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/value_util.h"
+
+namespace autofill_assistant {
+
+PresaveGeneratedPasswordAction::PresaveGeneratedPasswordAction(
+    ActionDelegate* delegate,
+    const ActionProto& proto)
+    : Action(delegate, proto) {
+  DCHECK(proto_.has_presave_generated_password());
+}
+
+PresaveGeneratedPasswordAction::~PresaveGeneratedPasswordAction() {}
+
+void PresaveGeneratedPasswordAction::InternalProcessAction(
+    ProcessActionCallback callback) {
+  callback_ = std::move(callback);
+
+  auto presave_password = proto_.presave_generated_password();
+
+  if (presave_password.memory_key().empty()) {
+    VLOG(1) << "PresaveGeneratedPasswordAction: empty |memory_key|";
+    EndAction(ClientStatus(INVALID_ACTION));
+    return;
+  }
+
+  if (!delegate_->GetUserData()->has_additional_value(
+          presave_password.memory_key()) ||
+      delegate_->GetUserData()
+              ->additional_value(presave_password.memory_key())
+              ->strings()
+              .values()
+              .size() != 1) {
+    VLOG(1) << "PresaveGeneratedPasswordAction: requested key '"
+            << presave_password.memory_key()
+            << "' not available in client memory";
+    EndAction(ClientStatus(PRECONDITION_FAILED));
+    return;
+  }
+
+  if (!delegate_->GetUserData()->selected_login_.has_value()) {
+    VLOG(1) << "PresaveGeneratedPasswordAction: requested login details "
+               "not available in client memory.";
+    EndAction(ClientStatus(PRECONDITION_FAILED));
+    return;
+  }
+
+  if (!delegate_->GetUserData()->password_form_data_.has_value()) {
+    VLOG(1) << "PresaveGeneratedPasswordAction: requested form data details "
+               "not available in client memory.";
+    EndAction(ClientStatus(PRECONDITION_FAILED));
+    return;
+  }
+
+  std::string password = delegate_->GetUserData()
+                             ->additional_value(presave_password.memory_key())
+                             ->strings()
+                             .values(0);
+
+  delegate_->GetWebsiteLoginManager()->PresaveGeneratedPassword(
+      *delegate_->GetUserData()->selected_login_, password,
+      *delegate_->GetUserData()->password_form_data_,
+      base::BindOnce(&PresaveGeneratedPasswordAction::EndAction,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     ClientStatus(ACTION_APPLIED)));
+}
+
+void PresaveGeneratedPasswordAction::EndAction(const ClientStatus& status) {
+  UpdateProcessedAction(status);
+  std::move(callback_).Run(std::move(processed_action_proto_));
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/presave_generated_password_action.h b/components/autofill_assistant/browser/actions/presave_generated_password_action.h
new file mode 100644
index 0000000..e48b878
--- /dev/null
+++ b/components/autofill_assistant/browser/actions/presave_generated_password_action.h
@@ -0,0 +1,49 @@
+// 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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_PRESAVE_GENERATED_PASSWORD_ACTION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_PRESAVE_GENERATED_PASSWORD_ACTION_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/user_data.h"
+
+namespace autofill_assistant {
+
+// Action to presave a generated password. It is only possible if password
+// has been already generated using |GeneratePasswordAction|.
+// Presaving stores a generated password with empty username for the cases
+// when Chrome misses or misclassifies a successful submission. Thus, even if
+// a site saves/updates the password and Chrome doesn't, the generated
+// password will be in the password store.
+// A generated password is presaved after form filling.
+class PresaveGeneratedPasswordAction : public Action {
+ public:
+  explicit PresaveGeneratedPasswordAction(ActionDelegate* delegate,
+                                          const ActionProto& proto);
+  ~PresaveGeneratedPasswordAction() override;
+
+  PresaveGeneratedPasswordAction(const PresaveGeneratedPasswordAction&) =
+      delete;
+  PresaveGeneratedPasswordAction& operator=(
+      const PresaveGeneratedPasswordAction&) = delete;
+
+ private:
+  // Overrides Action:
+  void InternalProcessAction(ProcessActionCallback callback) override;
+
+  void EndAction(const ClientStatus& status);
+
+  Selector selector_;
+  ProcessActionCallback callback_;
+  base::WeakPtrFactory<PresaveGeneratedPasswordAction> weak_ptr_factory_{this};
+};
+
+}  // namespace autofill_assistant
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_PRESAVE_GENERATED_PASSWORD_ACTION_H_
diff --git a/components/autofill_assistant/browser/actions/presave_generated_password_action_unittest.cc b/components/autofill_assistant/browser/actions/presave_generated_password_action_unittest.cc
new file mode 100644
index 0000000..e403c9e
--- /dev/null
+++ b/components/autofill_assistant/browser/actions/presave_generated_password_action_unittest.cc
@@ -0,0 +1,123 @@
+// 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 "components/autofill_assistant/browser/actions/presave_generated_password_action.h"
+
+#include <string>
+#include <utility>
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/mock_website_login_manager.h"
+#include "components/autofill_assistant/browser/value_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+const char kFakeUrl[] = "https://www.example.com";
+const char kFakeUsername[] = "user@example.com";
+const char kGeneratedPassword[] = "m-W2b-_.7Fu9A.A";
+const char kMemoryKeyForGeneratedPassword[] = "memory-key-for-generation";
+}  // namespace
+
+namespace autofill_assistant {
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Pointee;
+using ::testing::Property;
+using ::testing::Return;
+
+class PresaveGeneratedPasswordActionTest : public testing::Test {
+ public:
+  void SetUp() override {
+    ON_CALL(mock_action_delegate_, GetWebsiteLoginManager)
+        .WillByDefault(Return(&mock_website_login_manager_));
+
+    ON_CALL(mock_action_delegate_, GetUserData)
+        .WillByDefault(Return(&user_data_));
+  }
+
+ protected:
+  MockActionDelegate mock_action_delegate_;
+  MockWebsiteLoginManager mock_website_login_manager_;
+  base::MockCallback<Action::ProcessActionCallback> callback_;
+  ActionProto proto_;
+  UserData user_data_;
+};
+
+TEST_F(PresaveGeneratedPasswordActionTest, PresaveGeneratedPassword) {
+  user_data_.selected_login_ = base::make_optional<WebsiteLoginManager::Login>(
+      GURL(kFakeUrl), kFakeUsername);
+  user_data_.additional_values_[kMemoryKeyForGeneratedPassword] =
+      SimpleValue(std::string(kGeneratedPassword));
+  user_data_.password_form_data_ = autofill::FormData();
+
+  PresaveGeneratedPasswordProto* presave_password_proto =
+      proto_.mutable_presave_generated_password();
+  presave_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
+
+  PresaveGeneratedPasswordAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(mock_website_login_manager_,
+              OnPresaveGeneratedPassword(_, kGeneratedPassword, _, _))
+      .Times(1);
+
+  action.ProcessAction(callback_.Get());
+}
+
+TEST_F(PresaveGeneratedPasswordActionTest, LoginDataMissing) {
+  user_data_.additional_values_[kMemoryKeyForGeneratedPassword] =
+      SimpleValue(std::string(kGeneratedPassword));
+  user_data_.password_form_data_ = autofill::FormData();
+
+  PresaveGeneratedPasswordProto* presave_password_proto =
+      proto_.mutable_presave_generated_password();
+  presave_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
+
+  PresaveGeneratedPasswordAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              PRECONDITION_FAILED))));
+
+  action.ProcessAction(callback_.Get());
+}
+
+TEST_F(PresaveGeneratedPasswordActionTest, GeneratedPasswordMissing) {
+  user_data_.selected_login_ = base::make_optional<WebsiteLoginManager::Login>(
+      GURL(kFakeUrl), kFakeUsername);
+  user_data_.password_form_data_ = autofill::FormData();
+
+  PresaveGeneratedPasswordProto* presave_password_proto =
+      proto_.mutable_presave_generated_password();
+  presave_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
+
+  PresaveGeneratedPasswordAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              PRECONDITION_FAILED))));
+
+  action.ProcessAction(callback_.Get());
+}
+
+TEST_F(PresaveGeneratedPasswordActionTest, FormDataMissing) {
+  user_data_.selected_login_ = base::make_optional<WebsiteLoginManager::Login>(
+      GURL(kFakeUrl), kFakeUsername);
+  user_data_.additional_values_[kMemoryKeyForGeneratedPassword] =
+      SimpleValue(std::string(kGeneratedPassword));
+
+  PresaveGeneratedPasswordProto* presave_password_proto =
+      proto_.mutable_presave_generated_password();
+  presave_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
+
+  PresaveGeneratedPasswordAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              PRECONDITION_FAILED))));
+
+  action.ProcessAction(callback_.Get());
+}
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc
index 2f4d16f..aeda795 100644
--- a/components/autofill_assistant/browser/protocol_utils.cc
+++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -18,6 +18,7 @@
 #include "components/autofill_assistant/browser/actions/highlight_element_action.h"
 #include "components/autofill_assistant/browser/actions/navigate_action.h"
 #include "components/autofill_assistant/browser/actions/popup_message_action.h"
+#include "components/autofill_assistant/browser/actions/presave_generated_password_action.h"
 #include "components/autofill_assistant/browser/actions/prompt_action.h"
 #include "components/autofill_assistant/browser/actions/save_generated_password_action.h"
 #include "components/autofill_assistant/browser/actions/select_option_action.h"
@@ -225,6 +226,8 @@
       return std::make_unique<SaveGeneratedPasswordAction>(delegate, action);
     case ActionProto::ActionInfoCase::kConfigureUiState:
       return std::make_unique<ConfigureUiStateAction>(delegate, action);
+    case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
+      return std::make_unique<PresaveGeneratedPasswordAction>(delegate, action);
     case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: {
       VLOG(1) << "Encountered action with ACTION_INFO_NOT_SET";
       return std::make_unique<UnsupportedAction>(delegate, action);
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index a68698d..c2cf91b 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -209,6 +209,7 @@
     case ActionProto::ActionInfoCase::kGeneratePasswordForFormField:
     case ActionProto::ActionInfoCase::kSaveGeneratedPassword:
     case ActionProto::ActionInfoCase::kConfigureUiState:
+    case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
     case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET:
       return false;
   }
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 52fbb5a..50ead50 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -253,7 +253,8 @@
       base::OnceCallback<void(const ClientStatus&)>
           view_inflation_finished_callback) override;
   void ClearGenericUi() override;
-  void SetOverlayBehavior(ConfigureUiStateProto::OverlayBehavior) override;
+  void SetOverlayBehavior(
+      ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
 
  private:
   // Helper for WaitForElementVisible that keeps track of the state required to
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 47a0971..d1c4b04 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -497,6 +497,7 @@
     GeneratePasswordForFormFieldProto generate_password_for_form_field = 52;
     SaveGeneratedPasswordProto save_generated_password = 53;
     ConfigureUiStateProto configure_ui_state = 54;
+    PresaveGeneratedPasswordProto presave_generated_password = 55;
   }
 
   // Set to true to make the client remove any contextual information if the
@@ -1902,8 +1903,7 @@
 
 // Asks the password manager to generate a suitable password for |element|. The
 // generated password can be filled in subsequent SetFormFieldValueProto
-// actions. Generated password will be presaved to password store,
-// login details need to be available in the client memory for this action.
+// actions.
 message GeneratePasswordForFormFieldProto {
   // A reference to the form element for which to generate a password.
   optional SelectorProto element = 1;
@@ -1911,6 +1911,15 @@
   optional string memory_key = 2;
 }
 
+// Presaves generated password to the password store.
+// Presaving stores a generated password with empty username.
+// Only possible if a password has already been generated using
+// |GeneratePasswordForFormFieldProto|.
+message PresaveGeneratedPasswordProto {
+  // The client memory key of the stored password.
+  optional string memory_key = 1;
+}
+
 // Asks the password save manager to save generated password after successful
 // submission.
 message SaveGeneratedPasswordProto {
@@ -1924,10 +1933,6 @@
     // The overlay is decided according to the state the client is in.
     DEFAULT = 0;
     // The overlay is always hidden.
-    // At the moment this also changes the behavior of the back button and it
-    // should only be used for browse mode.
-    // TODO(HLUCA): add a separate setting in this action to configure the back
-    // button behavior.
     HIDDEN = 1;
   }
   optional OverlayBehavior overlay_behavior = 1;
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h
index 36b1c1e..acc2859f 100644
--- a/components/autofill_assistant/browser/ui_delegate.h
+++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -237,6 +237,8 @@
   // The generic user interface to show, if any.
   virtual const GenericUserInterfaceProto* GetGenericUiProto() const = 0;
 
+  // Whether the overlay should be determined based on AA state or always
+  // hidden.
   virtual bool ShouldShowOverlay() const = 0;
 
   // Notifies the UI deleagate that it should shut down.
diff --git a/components/autofill_assistant/browser/user_data.h b/components/autofill_assistant/browser/user_data.h
index 9e65d6d..e6d7375 100644
--- a/components/autofill_assistant/browser/user_data.h
+++ b/components/autofill_assistant/browser/user_data.h
@@ -146,6 +146,12 @@
   // The additional value for |key|, or nullptr if it does not exist.
   const ValueProto* additional_value(const std::string& key) const;
 
+  // The form data of the password change form. This is stored at the time of
+  // password generation (GeneratePasswordForFormFieldProto) to allow a
+  // subsequent PresaveGeneratedPasswordProto to presave the password prior to
+  // submission.
+  base::Optional<autofill::FormData> password_form_data_;
+
   std::string GetAllAddressKeyNames() const;
 };
 
diff --git a/components/bookmarks/browser/bookmark_client.cc b/components/bookmarks/browser/bookmark_client.cc
index 5f5510d..6b1ae8c 100644
--- a/components/bookmarks/browser/bookmark_client.cc
+++ b/components/bookmarks/browser/bookmark_client.cc
@@ -10,13 +10,8 @@
 
 void BookmarkClient::Init(BookmarkModel* model) {}
 
-bool BookmarkClient::PreferTouchIcon() {
-  return false;
-}
-
 base::CancelableTaskTracker::TaskId BookmarkClient::GetFaviconImageForPageURL(
     const GURL& page_url,
-    favicon_base::IconType type,
     favicon_base::FaviconImageCallback callback,
     base::CancelableTaskTracker* tracker) {
   return base::CancelableTaskTracker::kBadTaskId;
diff --git a/components/bookmarks/browser/bookmark_client.h b/components/bookmarks/browser/bookmark_client.h
index 7ad2a46..f08f7e0 100644
--- a/components/bookmarks/browser/bookmark_client.h
+++ b/components/bookmarks/browser/bookmark_client.h
@@ -6,14 +6,14 @@
 #define COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_CLIENT_H_
 
 #include <cstdint>
-#include <map>
+#include <string>
+#include <unordered_map>
 #include <utility>
 
 #include "base/callback_forward.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/favicon_base/favicon_callback.h"
-#include "components/favicon_base/favicon_types.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class GURL;
@@ -46,20 +46,13 @@
   // Called during initialization of BookmarkModel.
   virtual void Init(BookmarkModel* model);
 
-  // Returns true if the embedder favors touch icons over favicons.
-  virtual bool PreferTouchIcon();
-
-  // Requests a favicon from the history cache for the web page at |page_url|.
-  // |callback| is run when the favicon has been fetched. If |type| is:
-  // - favicon_base::IconType::kFavicon, the returned gfx::Image is a
-  //   multi-resolution image of gfx::kFaviconSize DIP width and height. The
-  //   data from the history cache is resized if need be.
-  // - not favicon_base::IconType::kFavicon, the returned gfx::Image is a
-  //   single-resolution image with the largest bitmap in the history cache for
-  //   |page_url| and |type|.
+  // Requests a favicon from the history cache for the web page at |page_url|
+  // for icon type favicon_base::IconType::kFavicon. |callback| is run when the
+  // favicon has been fetched, which returns gfx::Image is a multi-resolution
+  // image of gfx::kFaviconSize DIP width and height. The data from the history
+  // cache is resized if need be.
   virtual base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
       const GURL& page_url,
-      favicon_base::IconType type,
       favicon_base::FaviconImageCallback callback,
       base::CancelableTaskTracker* tracker);
 
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc
index 39e380e..fffeb634 100644
--- a/components/bookmarks/browser/bookmark_model.cc
+++ b/components/bookmarks/browser/bookmark_model.cc
@@ -357,19 +357,11 @@
   DCHECK(node);
   if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
     BookmarkNode* mutable_node = AsMutable(node);
-    LoadFavicon(mutable_node, client_->PreferTouchIcon()
-                                  ? favicon_base::IconType::kTouchIcon
-                                  : favicon_base::IconType::kFavicon);
+    LoadFavicon(mutable_node);
   }
   return node->favicon();
 }
 
-favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(node);
-  return node->favicon_type();
-}
-
 void BookmarkModel::SetTitle(const BookmarkNode* node,
                              const base::string16& title) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -907,7 +899,6 @@
 
 void BookmarkModel::OnFaviconDataAvailable(
     BookmarkNode* node,
-    favicon_base::IconType icon_type,
     const favicon_base::FaviconImageResult& image_result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(node);
@@ -915,22 +906,16 @@
   node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
   node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
   if (!image_result.image.IsEmpty()) {
-    node->set_favicon_type(icon_type);
     node->set_favicon(image_result.image);
     node->set_icon_url(image_result.icon_url);
     FaviconLoaded(node);
-  } else if (icon_type == favicon_base::IconType::kTouchIcon) {
-    // Couldn't load the touch icon, fallback to the regular favicon.
-    DCHECK(client_->PreferTouchIcon());
-    LoadFavicon(node, favicon_base::IconType::kFavicon);
   } else {
     // No favicon available, but we still notify observers.
     FaviconLoaded(node);
   }
 }
 
-void BookmarkModel::LoadFavicon(BookmarkNode* node,
-                                favicon_base::IconType icon_type) {
+void BookmarkModel::LoadFavicon(BookmarkNode* node) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (node->is_folder())
@@ -940,9 +925,9 @@
   node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
   base::CancelableTaskTracker::TaskId taskId =
       client_->GetFaviconImageForPageURL(
-          node->url(), icon_type,
+          node->url(),
           base::BindOnce(&BookmarkModel::OnFaviconDataAvailable,
-                         base::Unretained(this), node, icon_type),
+                         base::Unretained(this), node),
           &cancelable_task_tracker_);
   if (taskId != base::CancelableTaskTracker::kBadTaskId)
     node->set_favicon_load_task_id(taskId);
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h
index fce7bfd..544b063 100644
--- a/components/bookmarks/browser/bookmark_model.h
+++ b/components/bookmarks/browser/bookmark_model.h
@@ -11,6 +11,7 @@
 #include <map>
 #include <memory>
 #include <set>
+#include <string>
 #include <vector>
 
 #include "base/check_op.h"
@@ -170,10 +171,6 @@
   // LOADING_FAVICON (with the exception of folders, where the call is a no-op).
   const gfx::Image& GetFavicon(const BookmarkNode* node);
 
-  // Returns the type of the favicon for |node|. If the favicon has not yet
-  // been loaded, it returns |favicon_base::IconType::kInvalid|.
-  favicon_base::IconType GetFaviconType(const BookmarkNode* node);
-
   // Sets the title of |node|.
   void SetTitle(const BookmarkNode* node, const base::string16& title);
 
@@ -350,12 +347,11 @@
   // favicon, FaviconLoaded is invoked.
   void OnFaviconDataAvailable(
       BookmarkNode* node,
-      favicon_base::IconType icon_type,
       const favicon_base::FaviconImageResult& image_result);
 
   // Invoked from the node to load the favicon. Requests the favicon from the
   // favicon service.
-  void LoadFavicon(BookmarkNode* node, favicon_base::IconType icon_type);
+  void LoadFavicon(BookmarkNode* node);
 
   // Called to notify the observers that the favicon has been loaded.
   void FaviconLoaded(const BookmarkNode* node);
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc
index b02b2c4a..6473790 100644
--- a/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -33,6 +33,7 @@
 #include "components/bookmarks/test/bookmark_test_helpers.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
 #include "components/favicon_base/favicon_callback.h"
+#include "components/favicon_base/favicon_types.h"
 #include "components/query_parser/query_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -1362,8 +1363,7 @@
       favicon_base::FaviconImageResult image_result;
       image_result.image = image;
       image_result.icon_url = icon_url;
-      model_->OnFaviconDataAvailable(node, favicon_base::IconType::kFavicon,
-                                     image_result);
+      model_->OnFaviconDataAvailable(node, image_result);
   }
 
   bool WasNodeUpdated(const BookmarkNode* node) {
diff --git a/components/bookmarks/browser/bookmark_node.cc b/components/bookmarks/browser/bookmark_node.cc
index 57e78ce6..38c9e23 100644
--- a/components/bookmarks/browser/bookmark_node.cc
+++ b/components/bookmarks/browser/bookmark_node.cc
@@ -128,7 +128,6 @@
       url_(url),
       type_(type),
       date_added_(base::Time::Now()),
-      favicon_type_(favicon_base::IconType::kInvalid),
       is_permanent_node_(is_permanent_node) {
   DCHECK((type == URL) != url.is_empty());
   DCHECK(base::IsValidGUIDOutputString(guid));
@@ -137,7 +136,6 @@
 void BookmarkNode::InvalidateFavicon() {
   icon_url_.reset();
   favicon_ = gfx::Image();
-  favicon_type_ = favicon_base::IconType::kInvalid;
   favicon_state_ = INVALID_FAVICON;
 }
 
diff --git a/components/bookmarks/browser/bookmark_node.h b/components/bookmarks/browser/bookmark_node.h
index dabae5f..cae4e89 100644
--- a/components/bookmarks/browser/bookmark_node.h
+++ b/components/bookmarks/browser/bookmark_node.h
@@ -7,13 +7,14 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <memory>
+#include <string>
 
 #include "base/macros.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/time/time.h"
 #include "components/bookmarks/browser/titled_url_node.h"
-#include "components/favicon_base/favicon_types.h"
 #include "ui/base/models/tree_node_model.h"
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
@@ -154,9 +155,6 @@
   const gfx::Image& favicon() const { return favicon_; }
   void set_favicon(const gfx::Image& icon) { favicon_ = icon; }
 
-  favicon_base::IconType favicon_type() const { return favicon_type_; }
-  void set_favicon_type(favicon_base::IconType type) { favicon_type_ = type; }
-
   FaviconState favicon_state() const { return favicon_state_; }
   void set_favicon_state(FaviconState state) { favicon_state_ = state; }
 
@@ -193,9 +191,6 @@
   // The favicon of this node.
   gfx::Image favicon_;
 
-  // The type of favicon currently loaded.
-  favicon_base::IconType favicon_type_;
-
   // The URL of the node's favicon.
   std::unique_ptr<GURL> icon_url_;
 
diff --git a/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
index cbf16f1a..4de3207 100644
--- a/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
@@ -5,6 +5,7 @@
 #include "components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h"
 
 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 
 namespace internal {
 
@@ -32,13 +33,16 @@
 BackForwardCachePageLoadMetricsObserver::OnEnterBackForwardCache(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
   in_back_forward_cache_ = true;
-  DumpLayoutShiftScoreAfterBackForwardCacheRestore(timing);
+  MaybeRecordLayoutShiftScoreAfterBackForwardCacheRestore(timing);
   return CONTINUE_OBSERVING;
 }
 
 void BackForwardCachePageLoadMetricsObserver::OnRestoreFromBackForwardCache(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
+    const page_load_metrics::mojom::PageLoadTiming& timing,
+    content::NavigationHandle* navigation_handle) {
   in_back_forward_cache_ = false;
+  back_forward_cache_navigation_ids_.push_back(
+      navigation_handle->GetNavigationId());
 }
 
 void BackForwardCachePageLoadMetricsObserver::
@@ -53,6 +57,12 @@
     PAGE_LOAD_HISTOGRAM(
         internal::kHistogramFirstPaintAfterBackForwardCacheRestore,
         first_paint);
+
+    ukm::builders::HistoryNavigation builder(
+        GetUkmSourceIdForBackForwardCacheRestore(index));
+    builder.SetNavigationToFirstPaintAfterBackForwardCacheRestore(
+        first_paint.InMilliseconds());
+    builder.Record(ukm::UkmRecorder::Get());
   }
 }
 
@@ -70,6 +80,12 @@
         internal::kHistogramFirstInputDelayAfterBackForwardCacheRestore,
         *first_input_delay, base::TimeDelta::FromMilliseconds(1),
         base::TimeDelta::FromSeconds(60), 50);
+
+    ukm::builders::HistoryNavigation builder(
+        GetUkmSourceIdForBackForwardCacheRestore(index));
+    builder.SetFirstInputDelayAfterBackForwardCacheRestore(
+        first_input_delay.value().InMilliseconds());
+    builder.Record(ukm::UkmRecorder::Get());
   }
 }
 
@@ -83,16 +99,16 @@
 void BackForwardCachePageLoadMetricsObserver::OnComplete(
     const page_load_metrics::mojom::PageLoadTiming& timing) {
   // If the page is in the back-forward cache and OnComplete is called, the page
-  // is evicted from the cache. Do not dump CLS here as we have already recorded
-  // it in OnEnterBackForwardCache.
+  // is evicted from the cache. Do not record CLS here as we have already
+  // recorded it in OnEnterBackForwardCache.
   if (in_back_forward_cache_)
     return;
 
-  DumpLayoutShiftScoreAfterBackForwardCacheRestore(timing);
+  MaybeRecordLayoutShiftScoreAfterBackForwardCacheRestore(timing);
 }
 
 void BackForwardCachePageLoadMetricsObserver::
-    DumpLayoutShiftScoreAfterBackForwardCacheRestore(
+    MaybeRecordLayoutShiftScoreAfterBackForwardCacheRestore(
         const page_load_metrics::mojom::PageLoadTiming& timing) {
   if (!last_main_frame_layout_shift_score_.has_value()) {
     DCHECK(!last_layout_shift_score_.has_value());
@@ -101,8 +117,8 @@
     last_layout_shift_score_ =
         GetDelegate().GetPageRenderData().layout_shift_score;
 
-    // When DumpLayoutShiftScore is called first time, the page has not been in
-    // back-forward cache. The scores not after the page is restored from back-
+    // When this function is called first time, the page has not been in back-
+    // forward cache. The scores not after the page is restored from back-
     // forward cache are recorded in other observers like
     // UkmPageLoadMetricsObserver.
     return;
@@ -125,10 +141,31 @@
       internal::kHistogramCumulativeShiftScoreAfterBackForwardCacheRestore,
       page_load_metrics::LayoutShiftUmaValue(layout_shift_score));
 
+  ukm::builders::HistoryNavigation builder(
+      GetLastUkmSourceIdForBackForwardCacheRestore());
+  builder.SetCumulativeShiftScoreAfterBackForwardCacheRestore(
+      page_load_metrics::LayoutShiftUkmValue(layout_main_frame_shift_score));
+  builder.Record(ukm::UkmRecorder::Get());
+
   last_main_frame_layout_shift_score_ =
       GetDelegate().GetMainFrameRenderData().layout_shift_score;
   last_layout_shift_score_ =
       GetDelegate().GetPageRenderData().layout_shift_score;
+}
 
-  // TODO(hajimehoshi): Add UKM
+int64_t BackForwardCachePageLoadMetricsObserver::
+    GetUkmSourceIdForBackForwardCacheRestore(size_t index) const {
+  DCHECK_GT(back_forward_cache_navigation_ids_.size(), index);
+  int64_t navigation_id = back_forward_cache_navigation_ids_[index];
+  DCHECK_NE(ukm::kInvalidSourceId, navigation_id);
+  return ukm::ConvertToSourceId(navigation_id,
+                                ukm::SourceIdType::NAVIGATION_ID);
+}
+
+int64_t BackForwardCachePageLoadMetricsObserver::
+    GetLastUkmSourceIdForBackForwardCacheRestore() const {
+  int64_t navigation_id = back_forward_cache_navigation_ids_.back();
+  DCHECK_NE(ukm::kInvalidSourceId, navigation_id);
+  return ukm::ConvertToSourceId(navigation_id,
+                                ukm::SourceIdType::NAVIGATION_ID);
 }
diff --git a/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h
index 105ef3537..4eff886 100644
--- a/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h
@@ -29,7 +29,8 @@
   OnEnterBackForwardCache(
       const page_load_metrics::mojom::PageLoadTiming& timing) override;
   void OnRestoreFromBackForwardCache(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+      const page_load_metrics::mojom::PageLoadTiming& timing,
+      content::NavigationHandle* navigation_handle) override;
   void OnFirstPaintAfterBackForwardCacheRestoreInPage(
       const page_load_metrics::mojom::BackForwardCacheTiming& timing,
       size_t index) override;
@@ -42,14 +43,20 @@
       const page_load_metrics::mojom::PageLoadTiming& timing) override;
 
  private:
-  // Dumps the layout shift score after the page is restored from the back-
+  // Records the layout shift score after the page is restored from the back-
   // forward cache. This is called when the page is navigated away, i.e., when
   // the page enters to the cache, or the page is closed. In the first call, as
-  // the page has not been in the back-forward cache yet, this doesn't dump the
-  // scores.
-  void DumpLayoutShiftScoreAfterBackForwardCacheRestore(
+  // the page has not been in the back-forward cache yet, this doesn't record
+  // the scores.
+  void MaybeRecordLayoutShiftScoreAfterBackForwardCacheRestore(
       const page_load_metrics::mojom::PageLoadTiming& timing);
 
+  // Returns the UKM source ID for index-th back-foward restore navigation.
+  int64_t GetUkmSourceIdForBackForwardCacheRestore(size_t index) const;
+
+  // Returns the UKM source ID for the last back-foward restore navigation.
+  int64_t GetLastUkmSourceIdForBackForwardCacheRestore() const;
+
   // Whether the page is currently in the back-forward cache or not.
   bool in_back_forward_cache_ = false;
 
@@ -58,6 +65,10 @@
   base::Optional<double> last_main_frame_layout_shift_score_;
   base::Optional<double> last_layout_shift_score_;
 
+  // IDs for the navigations when the page is restored from the back-forward
+  // cache.
+  std::vector<ukm::SourceId> back_forward_cache_navigation_ids_;
+
   DISALLOW_COPY_AND_ASSIGN(BackForwardCachePageLoadMetricsObserver);
 };
 
diff --git a/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.cc
index a6f18f2c..cba4ff8 100644
--- a/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.cc
@@ -1207,7 +1207,8 @@
 }
 
 void CorePageLoadMetricsObserver::OnRestoreFromBackForwardCache(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
+    const page_load_metrics::mojom::PageLoadTiming& timing,
+    content::NavigationHandle* navigation_handle) {
   // This never reaches yet because OnEnterBackForwardCache returns
   // STOP_OBSERVING.
   // TODO(hajimehoshi): After changing OnEnterBackForwardCache to continue
diff --git a/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.h
index 3fb6e3c..7eab43d 100644
--- a/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/observers/core_page_load_metrics_observer.h
@@ -216,7 +216,8 @@
   ObservePolicy OnEnterBackForwardCache(
       const page_load_metrics::mojom::PageLoadTiming& timing) override;
   void OnRestoreFromBackForwardCache(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+      const page_load_metrics::mojom::PageLoadTiming& timing,
+      content::NavigationHandle* navigation_handle) override;
   void OnLoadingBehaviorObserved(content::RenderFrameHost* rfh,
                                  int behavior_flags) override;
 
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.h b/components/page_load_metrics/browser/page_load_metrics_observer.h
index 7aab983..e461ca6 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -303,7 +303,8 @@
   // OnRestoreFromBackForwardCache is triggered when a page is restored from
   // the back-forward cache.
   virtual void OnRestoreFromBackForwardCache(
-      const mojom::PageLoadTiming& timing) {}
+      const mojom::PageLoadTiming& timing,
+      content::NavigationHandle* navigation_handle) {}
 
   // Called before OnCommit. The observer should return whether it wishes to
   // observe navigations whose main resource has MIME type |mine_type|. The
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
index cec06c91..677e2575 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
@@ -131,7 +131,7 @@
   virtual const LargestContentfulPaintHandler&
   GetExperimentalLargestContentfulPaintHandler() const = 0;
 
-  // UKM SourceId for the current page load.
+  // UKM source ID for the current page load.
   virtual ukm::SourceId GetSourceId() const = 0;
 
   // Whether the associated navigation is the first navigation in its associated
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 40a6f484..bee9bf8 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -959,8 +959,8 @@
     PageShown();
 
   for (const auto& observer : observers_) {
-    observer->OnRestoreFromBackForwardCache(
-        metrics_update_dispatcher_.timing());
+    observer->OnRestoreFromBackForwardCache(metrics_update_dispatcher_.timing(),
+                                            navigation_handle);
   }
 }
 
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 139dfba..d5f5c03 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -8,6 +8,7 @@
 #include <iterator>
 #include <map>
 #include <memory>
+#include <tuple>
 #include <utility>
 
 #include "base/bind.h"
@@ -40,22 +41,30 @@
   return form1.date_created > form2.date_created;
 }
 
+// Creates a base::flat_set of std::unique_ptr<autofill::PasswordForm> that uses
+// |key_getter| to compute the key used when comparing forms.
+template <typename KeyGetter>
+auto MakeFlatSet(KeyGetter key_getter) {
+  auto cmp = [key_getter](const auto& lhs, const auto& rhs) {
+    return key_getter(lhs) < key_getter(rhs);
+  };
+
+  return base::flat_set<std::unique_ptr<autofill::PasswordForm>, decltype(cmp)>(
+      cmp);
+}
+
 // Remove duplicates in |forms| before displaying them in the account chooser.
 void FilterDuplicates(
     std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) {
   std::vector<std::unique_ptr<autofill::PasswordForm>> federated_forms;
-  // The key is [username, signon_realm]. signon_realm is used only for PSL
-  // matches because those entries have it in the UI.
-  auto get_key = [](const auto& form) {
-    return std::make_pair(form->username_value, form->is_public_suffix_match
-                                                    ? form->signon_realm
-                                                    : std::string());
-  };
-  auto cmp = [&](const auto& lhs, const auto& rhs) {
-    return get_key(lhs) < get_key(rhs);
-  };
-  base::flat_set<std::unique_ptr<autofill::PasswordForm>, decltype(cmp)>
-      credentials(cmp);
+  // The key is [username, signon_realm, store]. signon_realm is used only for
+  // PSL matches because those entries have it in the UI.
+  auto credentials = MakeFlatSet(/*key_getter=*/[](const auto& form) {
+    return std::make_tuple(
+        form->username_value,
+        form->is_public_suffix_match ? form->signon_realm : std::string(),
+        form->in_store);
+  });
   for (auto& form : *forms) {
     if (!form->federation_origin.opaque()) {
       federated_forms.push_back(std::move(form));
@@ -65,7 +74,25 @@
         *result.first = std::move(form);
     }
   }
-  *forms = std::move(credentials).extract();
+  // |credentials| contains credentials from both profile and account stores.
+  // There could potentially be duplicate credentials with the same password in
+  // which case it doesn't make sense to show both in the UI. When such
+  // duplicates exist, we favor the account store version to make it clear in
+  // the UI that this credential is available on other devices.
+  auto credentials_with_unique_passwords =
+      MakeFlatSet(/*key_getter=*/[](const auto& form) {
+        return std::make_tuple(
+            form->username_value,
+            form->is_public_suffix_match ? form->signon_realm : std::string(),
+            form->password_value);
+      });
+
+  for (auto& form : std::move(credentials).extract()) {
+    auto result = credentials_with_unique_passwords.insert(std::move(form));
+    if (!result.second && form->IsUsingAccountStore())
+      *result.first = std::move(form);
+  }
+  *forms = std::move(credentials_with_unique_passwords).extract();
   std::move(federated_forms.begin(), federated_forms.end(),
             std::back_inserter(*forms));
 }
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
index 6dc7cc03..618fdd9 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/task_environment.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/test_password_store.h"
@@ -27,7 +28,22 @@
     return account_store_;
   }
 
+  // Store |forms| in |forms_passed_to_ui_|.
+  bool PromptUserToChooseCredentials(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
+      const url::Origin& origin,
+      const CredentialsCallback& callback) override {
+    forms_passed_to_ui_ = std::move(forms);
+    return true;
+  }
+
+  const std::vector<std::unique_ptr<autofill::PasswordForm>>&
+  forms_passed_to_ui() {
+    return forms_passed_to_ui_;
+  }
+
  private:
+  std::vector<std::unique_ptr<autofill::PasswordForm>> forms_passed_to_ui_;
   PasswordStore* profile_store_;
   PasswordStore* account_store_;
 };
@@ -66,8 +82,18 @@
     client_ = std::make_unique<TestPasswordManagerClient>(profile_store_.get(),
                                                           account_store_.get());
 
+    GURL url("http://www.example.com");
     ON_CALL(delegate_mock_, client)
         .WillByDefault(testing::Return(client_.get()));
+    ON_CALL(delegate_mock_, GetOrigin)
+        .WillByDefault(testing::Return(url::Origin::Create(url)));
+
+    form_.username_value = base::ASCIIToUTF16("Username");
+    form_.password_value = base::ASCIIToUTF16("Password");
+    form_.url = url;
+    form_.signon_realm = form_.url.GetOrigin().spec();
+    form_.scheme = autofill::PasswordForm::Scheme::kHtml;
+    form_.skip_zero_click = false;
   }
   ~CredentialManagerPendingRequestTaskTest() override = default;
 
@@ -78,11 +104,14 @@
     task_environment_.RunUntilIdle();
   }
 
+  TestPasswordManagerClient* client() { return client_.get(); }
+
  protected:
   testing::NiceMock<CredentialManagerPendingRequestTaskDelegateMock>
       delegate_mock_;
   scoped_refptr<TestPasswordStore> profile_store_;
   scoped_refptr<TestPasswordStore> account_store_;
+  autofill::PasswordForm form_;
 
  private:
   base::test::TaskEnvironment task_environment_;
@@ -118,4 +147,59 @@
   task.OnGetPasswordStoreResultsFrom(account_store_, {});
 }
 
+TEST_F(CredentialManagerPendingRequestTaskTest,
+       SameUsernameDifferentPasswordsInBothStores) {
+  // This is testing that when two credentials have the same username and
+  // different passwords from two store, both are passed to the UI.
+  CredentialManagerPendingRequestTask task(
+      &delegate_mock_, /*callback=*/base::DoNothing(),
+      CredentialMediationRequirement::kOptional, /*include_passwords=*/true,
+      /*request_federations=*/{}, StoresToQuery::kProfileAndAccountStores);
+
+  autofill::PasswordForm profile_form = form_;
+  profile_form.in_store = autofill::PasswordForm::Store::kProfileStore;
+  profile_form.password_value = base::ASCIIToUTF16("ProfilePassword");
+  std::vector<std::unique_ptr<autofill::PasswordForm>> profile_forms;
+  profile_forms.push_back(
+      std::make_unique<autofill::PasswordForm>(profile_form));
+
+  autofill::PasswordForm account_form = form_;
+  account_form.in_store = autofill::PasswordForm::Store::kAccountStore;
+  account_form.password_value = base::ASCIIToUTF16("AccountPassword");
+  std::vector<std::unique_ptr<autofill::PasswordForm>> account_forms;
+  account_forms.push_back(
+      std::make_unique<autofill::PasswordForm>(account_form));
+
+  task.OnGetPasswordStoreResultsFrom(profile_store_, std::move(profile_forms));
+  task.OnGetPasswordStoreResultsFrom(account_store_, std::move(account_forms));
+  EXPECT_EQ(2U, client()->forms_passed_to_ui().size());
+}
+
+TEST_F(CredentialManagerPendingRequestTaskTest,
+       SameUsernameSamePasswordsInBothStores) {
+  // This is testing that when two credentials have the same username and
+  //  passwords from two store, the account store version is passed to the UI.
+  CredentialManagerPendingRequestTask task(
+      &delegate_mock_, /*callback=*/base::DoNothing(),
+      CredentialMediationRequirement::kOptional, /*include_passwords=*/true,
+      /*request_federations=*/{}, StoresToQuery::kProfileAndAccountStores);
+
+  autofill::PasswordForm profile_form = form_;
+  profile_form.in_store = autofill::PasswordForm::Store::kProfileStore;
+  std::vector<std::unique_ptr<autofill::PasswordForm>> profile_forms;
+  profile_forms.push_back(
+      std::make_unique<autofill::PasswordForm>(profile_form));
+
+  autofill::PasswordForm account_form = form_;
+  account_form.in_store = autofill::PasswordForm::Store::kAccountStore;
+  std::vector<std::unique_ptr<autofill::PasswordForm>> account_forms;
+  account_forms.push_back(
+      std::make_unique<autofill::PasswordForm>(account_form));
+
+  task.OnGetPasswordStoreResultsFrom(profile_store_, std::move(profile_forms));
+  task.OnGetPasswordStoreResultsFrom(account_store_, std::move(account_forms));
+  ASSERT_EQ(1U, client()->forms_passed_to_ui().size());
+  EXPECT_TRUE(client()->forms_passed_to_ui()[0]->IsUsingAccountStore());
+}
+
 }  // namespace password_manager
diff --git a/components/services/storage/public/mojom/service_worker_storage_control.mojom b/components/services/storage/public/mojom/service_worker_storage_control.mojom
index f726dd4..741ec64 100644
--- a/components/services/storage/public/mojom/service_worker_storage_control.mojom
+++ b/components/services/storage/public/mojom/service_worker_storage_control.mojom
@@ -126,7 +126,8 @@
   // Reads a stored registration for |scope|.
   FindRegistrationForScope(url.mojom.Url scope) =>
       (ServiceWorkerFindRegistrationResult result);
-  // Reads a stored registration for |registration_id|.
+  // Reads a stored registration for |registration_id|. |origin| is to
+  // be used as a hint to look up the registration faster.
   FindRegistrationForId(int64 registration_id, url.mojom.Url? origin) =>
       (ServiceWorkerFindRegistrationResult result);
 
diff --git a/components/sync/protocol/README.md b/components/sync/protocol/README.md
new file mode 100644
index 0000000..f9ca2032
--- /dev/null
+++ b/components/sync/protocol/README.md
@@ -0,0 +1,18 @@
+Sync Protocol Style
+===================
+
+General guidelines:
+* Follow the [Protocol Buffers Style Guide](https://developers.google.com/protocol-buffers/docs/style)
+* Follow the [Proto Do's and Don'ts](http://go/protodosdonts) (sorry, Googlers only).
+* Maintain local consistency.
+* Use proto2 syntax.
+* **Always** get a review from someone in the OWNERS file in this folder. Don't use owners from higher-level folders, and **never** TBR changes!
+
+Some specific guidelines on top of the general ones above, or just things that often come up:
+* Enum entries should be in ALL_CAPS (different from C++!), and for new code, the first entry should be a `FOO_UNSPECIFIED = 0` one.
+* Proto changes also require corresponding changes in [proto_visitors.h](https://source.chromium.org/chromium/chromium/src/+/master:components/sync/protocol/proto_visitors.h) and (where appropriate) in [proto_enum_conversions.h/cc](https://source.chromium.org/chromium/chromium/src/+/master:components/sync/protocol/proto_enum_conversions.cc).
+* Backwards compatibility: In general, all changes must be fully backwards-compatible - consider that a single user might be running different versions of the browser simultaneously! Also note that Sync supports clients up to a few years old, so deprecating/removing an existing field is typically a multi-year process.
+* Deprecating fields:
+  * If the field **is** still accessed: Mark it as `[deprecated = true]`. This is the common case, since the browser typically needs to continue supporting the old field for backwards compatibility reasons.
+  * If the field **is not** accessed anymore (i.e. no non-ancient clients depend on the field being populated anymore, all migration code has been retired, etc): Remove the field, and add `reserved` entries for both its name and its tag number.
+* Deprecating enum values: This is particularly tricky, especially if the default value is not a `FOO_UNSPECIFIED` one (see above). A common pattern is prepending `DEPRECATED_` to the entry name.
diff --git a/components/sync/protocol/autofill_specifics.proto b/components/sync/protocol/autofill_specifics.proto
index c79d6dd9..e760ffab 100644
--- a/components/sync/protocol/autofill_specifics.proto
+++ b/components/sync/protocol/autofill_specifics.proto
@@ -63,7 +63,7 @@
   // "Ruiz y Picasso" containing a first last name, a conjunction (the y) and a
   // second last name.
   repeated string name_last_first = 27;
-  repeated string name_last_conjuction = 28;
+  repeated string name_last_conjunction = 28;
   repeated string name_last_second = 29;
   repeated string name_full = 21;
 
@@ -73,7 +73,7 @@
   repeated VerificationStatus name_middle_status = 32;
   repeated VerificationStatus name_last_status = 33;
   repeated VerificationStatus name_last_first_status = 34;
-  repeated VerificationStatus name_last_conjuction_status = 35;
+  repeated VerificationStatus name_last_conjunction_status = 35;
   repeated VerificationStatus name_last_second_status = 36;
   repeated VerificationStatus name_full_status = 37;
 
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index 8e7d13a3..6e4aa33 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -145,7 +145,7 @@
   VISIT_REP(name_first);
   VISIT_REP(name_middle);
   VISIT_REP(name_last_first);
-  VISIT_REP(name_last_conjuction);
+  VISIT_REP(name_last_conjunction);
   VISIT_REP(name_last_second);
   VISIT_REP(name_last);
   VISIT_REP(name_full);
@@ -154,7 +154,7 @@
   VISIT_REP(name_first_status);
   VISIT_REP(name_middle_status);
   VISIT_REP(name_last_first_status);
-  VISIT_REP(name_last_conjuction_status);
+  VISIT_REP(name_last_conjunction_status);
   VISIT_REP(name_last_second_status);
   VISIT_REP(name_last_status);
   VISIT_REP(name_full_status);
diff --git a/components/sync_bookmarks/DEPS b/components/sync_bookmarks/DEPS
index 09ded9e..4160f76 100644
--- a/components/sync_bookmarks/DEPS
+++ b/components/sync_bookmarks/DEPS
@@ -2,6 +2,7 @@
   "+components/bookmarks/browser",
   "+components/bookmarks/test",
   "+components/favicon/core",
+  "+components/favicon_base",
   "+components/history/core/browser",
   "+components/keyed_service",
   "+components/prefs",
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl.cc b/components/sync_bookmarks/bookmark_model_observer_impl.cc
index 4ea52c6c..19f4e5e 100644
--- a/components/sync_bookmarks/bookmark_model_observer_impl.cc
+++ b/components/sync_bookmarks/bookmark_model_observer_impl.cc
@@ -237,24 +237,11 @@
   const sync_pb::EntitySpecifics specifics = CreateSpecificsFromBookmarkNode(
       node, model, /*force_favicon_load=*/false, entity->has_final_guid());
 
-  // Check that we do not ignore changes when there is actual favicon in
-  // specifics.
-  DCHECK(model->GetFaviconType(node) == favicon_base::IconType::kFavicon ||
-         !specifics.bookmark().has_favicon());
-
   // TODO(crbug.com/1094825): implement |base_specifics_hash| similar to
   // ClientTagBasedModelTypeProcessor.
   if (!entity->MatchesFaviconHash(specifics.bookmark().favicon())) {
-    // Skip any changes if the node has touch favicon (which is not used for the
-    // specifics). MatchesFaviconHash would return false in this case and the
-    // entity would been committed without any favicon.
-    if (model->GetFaviconType(node) == favicon_base::IconType::kFavicon ||
-        model->GetFaviconType(node) == favicon_base::IconType::kInvalid ||
-        !base::FeatureList::IsEnabled(
-            switches::kSyncIgnoreChangesInTouchIcons)) {
-      ProcessUpdate(entity, specifics);
-      return;
-    }
+    ProcessUpdate(entity, specifics);
+    return;
   }
 
   // The favicon content didn't actually change, which means this event is
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
index a9f4e05..616c1d1 100644
--- a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/favicon_base/favicon_types.h"
 #include "components/sync/base/time.h"
 #include "components/sync/base/unique_position.h"
 #include "components/sync/driver/sync_driver_switches.h"
@@ -106,29 +107,19 @@
     return true;
   }
 
-  // This may be used to mimic iOS device behaviour.
-  void SetPreferTouchIcon(bool prefer_touch_icon) {
-    prefer_touch_icon_ = prefer_touch_icon;
-  }
-
   // bookmarks::TestBookmarkClient implementation.
   base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
       const GURL& page_url,
-      favicon_base::IconType type,
       favicon_base::FaviconImageCallback callback,
       base::CancelableTaskTracker* tracker) override {
     requests_per_page_url_[page_url].push_back(std::move(callback));
     return next_task_id_++;
   }
 
-  // BookmarkClient overrides.
-  bool PreferTouchIcon() override { return prefer_touch_icon_; }
-
  private:
   base::CancelableTaskTracker::TaskId next_task_id_ = 1;
   std::map<GURL, std::list<favicon_base::FaviconImageCallback>>
       requests_per_page_url_;
-  bool prefer_touch_icon_ = false;
 };
 
 class BookmarkModelObserverImplTest : public testing::Test {
@@ -904,134 +895,6 @@
   EXPECT_EQ(folder_entity->bookmark_node(), folder);
 }
 
-// Tests that on iOS devices there is no reupload of bookmarks after remote
-// update. This might happen in case when the remote bookmark contains favicon
-// and the local model has touch icon (which is not used in specifics).
-TEST_F(BookmarkModelObserverImplTest,
-       ShouldNotUpdateBookmarkOnTouchIconLoaded) {
-  bookmark_client()->SetPreferTouchIcon(true);
-
-  const GURL kBookmarkUrl("http://www.url.com");
-  const GURL kIconUrl("http://www.url.com/favicon.ico");
-  const SkColor kColor = SK_ColorRED;
-
-  // Simulate remote incremental update (without merge of favicon).
-  bookmark_model()->RemoveObserver(observer());
-
-  // Add a new node with specifics.
-  const bookmarks::BookmarkNode* bookmark_bar_node =
-      bookmark_model()->bookmark_bar_node();
-  const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
-      /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("title"),
-      kBookmarkUrl);
-
-  sync_pb::EntitySpecifics specifics =
-      CreateSpecificsFromBookmarkNode(bookmark_node, bookmark_model(),
-                                      /*force_favicon_load=*/false,
-                                      /*include_guid=*/true);
-
-  // Add favicon to the specifics to be sure that MatchesFaviconHash returns
-  // false.
-  const gfx::Image favicon_image = CreateTestImage(kColor);
-  scoped_refptr<base::RefCountedMemory> favicon_bytes =
-      favicon_image.As1xPNGBytes();
-  specifics.mutable_bookmark()->set_favicon(favicon_bytes->front(),
-                                            favicon_bytes->size());
-  specifics.mutable_bookmark()->set_icon_url(kIconUrl.spec());
-
-  const SyncedBookmarkTracker::Entity* entity = bookmark_tracker()->Add(
-      bookmark_node, "id", /*server_version=*/1, base::Time::Now(),
-      syncer::UniquePosition::InitialPosition(
-          syncer::UniquePosition::RandomSuffix())
-          .ToProto(),
-      specifics);
-
-  // Restore state.
-  bookmark_model()->AddObserver(observer());
-
-  ASSERT_FALSE(entity->IsUnsynced());
-
-  // Simulate BookmarkNodeFaviconChanged event (in normal case it would be
-  // called after storing remote favicon in the history backend).
-  //
-  // Invalidate bookmark favicon and load it again.
-  bookmark_model()->OnFaviconsChanged({kBookmarkUrl}, /*icon_url=*/GURL());
-  ASSERT_TRUE(bookmark_node->is_favicon_loading());
-  ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(kBookmarkUrl, kIconUrl,
-                                                       SK_ColorRED));
-  ASSERT_EQ(bookmark_model()->GetFaviconType(bookmark_node),
-            favicon_base::IconType::kTouchIcon);
-
-  EXPECT_FALSE(entity->IsUnsynced());
-}
-
-// Tests that there is still nudge for commit on touch icon loaded for the iOS
-// platform.
-TEST_F(BookmarkModelObserverImplTest, ShouldNudgeCommitOnTouchIconLoaded) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      switches::kSyncDoNotCommitBookmarksWithoutFavicon);
-  bookmark_client()->SetPreferTouchIcon(true);
-
-  const GURL kBookmarkUrl("http://www.url.com");
-  const GURL kIconUrl("http://www.url.com/favicon.ico");
-  const SkColor kColor = SK_ColorRED;
-
-  // Simulate remote incremental update (without merge of favicon).
-  bookmark_model()->RemoveObserver(observer());
-
-  // Add a new node with specifics and mark it unsynced.
-  const bookmarks::BookmarkNode* bookmark_bar_node =
-      bookmark_model()->bookmark_bar_node();
-  const bookmarks::BookmarkNode* bookmark_node = bookmark_model()->AddURL(
-      /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("title"),
-      kBookmarkUrl);
-
-  sync_pb::EntitySpecifics specifics =
-      CreateSpecificsFromBookmarkNode(bookmark_node, bookmark_model(),
-                                      /*force_favicon_load=*/false,
-                                      /*include_guid=*/true);
-
-  // Add favicon to the specifics to be sure that MatchesFaviconHash returns
-  // false.
-  const gfx::Image favicon_image = CreateTestImage(kColor);
-  scoped_refptr<base::RefCountedMemory> favicon_bytes =
-      favicon_image.As1xPNGBytes();
-  specifics.mutable_bookmark()->set_favicon(favicon_bytes->front(),
-                                            favicon_bytes->size());
-  specifics.mutable_bookmark()->set_icon_url(kIconUrl.spec());
-
-  const SyncedBookmarkTracker::Entity* entity = bookmark_tracker()->Add(
-      bookmark_node, "id", /*server_version=*/1, base::Time::Now(),
-      syncer::UniquePosition::InitialPosition(
-          syncer::UniquePosition::RandomSuffix())
-          .ToProto(),
-      specifics);
-  bookmark_tracker()->IncrementSequenceNumber(entity);
-
-  // Restore state.
-  bookmark_model()->AddObserver(observer());
-
-  ASSERT_TRUE(entity->IsUnsynced());
-  ASSERT_TRUE(entity->MatchesSpecificsHash(specifics));
-
-  EXPECT_CALL(*nudge_for_commit_closure(), Run());
-
-  // Simulate BookmarkNodeFaviconChanged event (in normal case it would be
-  // called after storing remote favicon in the history backend).
-  //
-  // Invalidate bookmark favicon and load it again.
-  bookmark_model()->OnFaviconsChanged({kBookmarkUrl}, /*icon_url=*/GURL());
-  ASSERT_TRUE(bookmark_node->is_favicon_loading());
-  ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(kBookmarkUrl, kIconUrl,
-                                                       SK_ColorRED));
-  ASSERT_EQ(bookmark_model()->GetFaviconType(bookmark_node),
-            favicon_base::IconType::kTouchIcon);
-
-  // Check that specifics haven't been changed.
-  EXPECT_TRUE(entity->MatchesSpecificsHash(specifics));
-}
-
 // Tests that the bookmark entity will be committed if its favicon is deleted.
 TEST_F(BookmarkModelObserverImplTest, ShouldCommitOnDeleteFavicon) {
   const GURL kBookmarkUrl("http://www.url.com");
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index f5311950..4c8cf3f 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -192,7 +192,6 @@
   // bookmarks::TestBookmarkClient implementation.
   base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
       const GURL& page_url,
-      favicon_base::IconType type,
       favicon_base::FaviconImageCallback callback,
       base::CancelableTaskTracker* tracker) override {
     favicon_image_callbacks_[next_task_id_] = std::move(callback);
diff --git a/components/sync_bookmarks/bookmark_specifics_conversions.cc b/components/sync_bookmarks/bookmark_specifics_conversions.cc
index 4318c61..c188e1e 100644
--- a/components/sync_bookmarks/bookmark_specifics_conversions.cc
+++ b/components/sync_bookmarks/bookmark_specifics_conversions.cc
@@ -241,12 +241,8 @@
   scoped_refptr<base::RefCountedMemory> favicon_bytes(nullptr);
   const gfx::Image& favicon = model->GetFavicon(node);
   // Check for empty images. This can happen if the favicon is still being
-  // loaded. Also avoid syncing touch icons.
-  if (!favicon.IsEmpty() &&
-      model->GetFaviconType(node) == favicon_base::IconType::kFavicon) {
-    // TODO(crbug.com/516866): Verify that this isn't  problematic for bookmarks
-    // created on iOS devices.
-
+  // loaded.
+  if (!favicon.IsEmpty()) {
     // Re-encode the BookmarkNode's favicon as a PNG.
     favicon_bytes = favicon.As1xPNGBytes();
   }
diff --git a/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc b/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc
index 252a22e..beee732 100644
--- a/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc
+++ b/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc
@@ -38,12 +38,11 @@
 
   base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
       const GURL& page_url,
-      favicon_base::IconType type,
       favicon_base::FaviconImageCallback callback,
       base::CancelableTaskTracker* tracker) override {
     ++load_favicon_requests;
     return TestBookmarkClient::GetFaviconImageForPageURL(
-        page_url, type, std::move(callback), tracker);
+        page_url, std::move(callback), tracker);
   }
 
   int GetLoadFaviconRequestsForTest() { return load_favicon_requests; }
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 0e28250..9e422ac 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -7522,8 +7522,9 @@
 }  // namespace
 
 // Check that swapped out frames cannot spawn JavaScript dialogs.
+// TODO(crbug.com/1112336): Flaky
 IN_PROC_BROWSER_TEST_P(NavigationControllerAlertDialogBrowserTest,
-                       NoDialogsFromSwappedOutFrames) {
+                       DISABLED_NoDialogsFromSwappedOutFrames) {
   // Start on a normal page.
   GURL url1 = embedded_test_server()->GetURL(
       "/navigation_controller/beforeunload_dialog.html");
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 24eb6b9..519c5fd 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1716,14 +1716,6 @@
     return;
   }
 
-  // If the page does not have any reporting endpoints, skip creating a
-  // reporter.
-  if (!render_frame_host_->cross_origin_opener_policy().reporting_endpoint &&
-      !render_frame_host_->cross_origin_opener_policy()
-           .report_only_reporting_endpoint) {
-    return;
-  }
-
   coop_reporter_ = std::make_unique<CrossOriginOpenerPolicyReporter>(
       storage_partition, frame_tree_node_->current_frame_host(),
       common_params_->url, render_frame_host_->cross_origin_opener_policy());
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index 4374d93..badd38f 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -5536,9 +5536,10 @@
 
 // Test to ensure that the error page navigation does not change
 // BrowsingInstances when window.open is present.
+// TODO(crbug.com/1110429): Disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(
     ProactivelySwapBrowsingInstancesCrossSiteSwapProcessTest,
-    ErrorPageNavigationWithWindowOpenDoesNotChangeBrowsingInstance) {
+    DISABLED_ErrorPageNavigationWithWindowOpenDoesNotChangeBrowsingInstance) {
   StartEmbeddedServer();
   GURL url(embedded_test_server()->GetURL("/title1.html"));
   GURL error_url(embedded_test_server()->GetURL("/empty.html"));
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index ce8e5ad..906a83b 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -7095,8 +7095,9 @@
 // loads an image with certificate errors, the browser should be
 // notified about the subresource with certificate errors and downgrade
 // the UI appropriately.
+// TODO(crbug.com/1105145): Flaky.
 IN_PROC_BROWSER_TEST_P(SitePerProcessIgnoreCertErrorsBrowserTest,
-                       SubresourceWithCertificateErrors) {
+                       DISABLED_SubresourceWithCertificateErrors) {
   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
   https_server.ServeFilesFromSourceDirectory(GetTestDataFilePath());
   SetupCrossSiteRedirector(&https_server);
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc
index a4f2b52..61eb1c0 100644
--- a/content/browser/tracing/startup_tracing_browsertest.cc
+++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -61,8 +61,9 @@
   DISALLOW_COPY_AND_ASSIGN(CommandlineStartupTracingTest);
 };
 
-// Failing on Android ASAN, Linux TSAN. crbug.com/1041392
+// Failing on Android/Win ASAN, Linux TSAN. crbug.com/1041392
 #if (defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)) || \
+    (defined(OS_WIN) && defined(ADDRESS_SANITIZER)) || \
     (defined(OS_LINUX) && defined(THREAD_SANITIZER))
 #define MAYBE_TestStartupTracing DISABLED_TestStartupTracing
 #else
diff --git a/content/browser/webui/web_ui_browsertest.cc b/content/browser/webui/web_ui_browsertest.cc
index 664ff17..1b6d765 100644
--- a/content/browser/webui/web_ui_browsertest.cc
+++ b/content/browser/webui/web_ui_browsertest.cc
@@ -14,11 +14,9 @@
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
 #include "content/browser/webui/content_web_ui_controller_factory.h"
-#include "content/browser/webui/web_ui_impl.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -54,10 +52,6 @@
         "notifyFinish",
         base::BindRepeating(&TestWebUIMessageHandler::OnNotifyFinish,
                             base::Unretained(this)));
-    web_ui()->RegisterMessageCallback(
-        "sendMessage",
-        base::BindRepeating(&TestWebUIMessageHandler::OnSendMessase,
-                            base::Unretained(this)));
   }
 
   void set_finish_closure(base::RepeatingClosure closure) {
@@ -78,13 +72,6 @@
       finish_closure_.Run();
   }
 
-  void OnSendMessase(const base::ListValue* args) {
-    AllowJavascript();
-
-    if (finish_closure_)
-      std::move(finish_closure_).Run();
-  }
-
   int message_requiring_gesture_count_ = 0;
   base::RepeatingClosure finish_closure_;
 };
@@ -351,34 +338,6 @@
             web_contents->GetTitle());
 }
 
-// Verify that we can successfully navigate to a chrome-untrusted:// URL
-// without a crash while WebUI::Send is being performed.
-IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, NavigateWhileWebUISend) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  auto* web_contents = shell()->web_contents();
-  ASSERT_TRUE(NavigateToURL(web_contents, GetWebUIURL(kChromeUIGpuHost)));
-
-  auto* test_handler = new TestWebUIMessageHandler;
-  web_contents->GetWebUI()->AddMessageHandler(base::WrapUnique(test_handler));
-
-  auto* webui = static_cast<WebUIImpl*>(web_contents->GetWebUI());
-  EXPECT_EQ(web_contents->GetMainFrame(), webui->frame_host_for_test());
-
-  test_handler->set_finish_closure(base::BindLambdaForTesting([&]() {
-    EXPECT_NE(web_contents->GetMainFrame(), webui->frame_host_for_test());
-  }));
-
-  web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
-      base::ASCIIToUTF16("onunload=function() { chrome.send('sendMessage')}"),
-      base::NullCallback());
-
-  RenderFrameDeletedObserver delete_observer(web_contents->GetMainFrame());
-  EXPECT_TRUE(NavigateToURL(
-      web_contents, embedded_test_server()->GetURL("/simple_page.html")));
-  delete_observer.WaitUntilDeleted();
-}
-
 class WebUIRequestSchemesTest : public ContentBrowserTest {
  public:
   WebUIRequestSchemesTest() {
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc
index 8753a5e..e3da9c29 100644
--- a/content/browser/webui/web_ui_impl.cc
+++ b/content/browser/webui/web_ui_impl.cc
@@ -203,11 +203,13 @@
 }
 
 bool WebUIImpl::CanCallJavascript() {
-  return (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
-              frame_host_->GetProcess()->GetID()) ||
+  RenderFrameHost* frame_host = web_contents_->GetMainFrame();
+  return frame_host &&
+         (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+              frame_host->GetProcess()->GetID()) ||
           // It's possible to load about:blank in a Web UI renderer.
           // See http://crbug.com/42547
-          frame_host_->GetLastCommittedURL().spec() == url::kAboutBlankURL);
+          frame_host->GetLastCommittedURL().spec() == url::kAboutBlankURL);
 }
 
 void WebUIImpl::CallJavascriptFunctionUnsafe(const std::string& function_name) {
diff --git a/content/browser/webui/web_ui_impl.h b/content/browser/webui/web_ui_impl.h
index 46a7d3b..f3fde2a 100644
--- a/content/browser/webui/web_ui_impl.h
+++ b/content/browser/webui/web_ui_impl.h
@@ -93,8 +93,6 @@
 
   const mojo::Remote<mojom::WebUI>& GetRemoteForTest() const { return remote_; }
 
-  RenderFrameHost* frame_host_for_test() const { return frame_host_; }
-
  private:
   class MainFrameNavigationObserver;
 
diff --git a/gpu/vulkan/vulkan_swap_chain.cc b/gpu/vulkan/vulkan_swap_chain.cc
index b939271..ca3d94c 100644
--- a/gpu/vulkan/vulkan_swap_chain.cc
+++ b/gpu/vulkan/vulkan_swap_chain.cc
@@ -405,7 +405,6 @@
   VkSemaphore vk_semaphore = CreateSemaphore(device);
   DCHECK(vk_semaphore != VK_NULL_HANDLE);
 
-  uint64_t kTimeout = UINT64_MAX;
 #if defined(USE_X11)
   // The xserver should still composite windows with a 1Hz fake vblank when
   // screen is off or the window is offscreen. However there is an xserver
@@ -417,8 +416,11 @@
   // be recreated.
   //
   // TODO(https://crbug.com/1098237): set correct timeout for ozone/x11.
-  if (!features::IsUsingOzonePlatform())
-    kTimeout = base::Time::kNanosecondsPerSecond * 2;
+  static uint64_t kTimeout = features::IsUsingOzonePlatform()
+                                 ? UINT64_MAX
+                                 : base::Time::kNanosecondsPerSecond * 2;
+#else
+  static uint64_t kTimeout = UINT64_MAX;
 #endif
   // Acquire the next image.
   uint32_t next_image;
diff --git a/ios/chrome/browser/bookmarks/bookmark_client_impl.cc b/ios/chrome/browser/bookmarks/bookmark_client_impl.cc
index 33536a21..b854960 100644
--- a/ios/chrome/browser/bookmarks/bookmark_client_impl.cc
+++ b/ios/chrome/browser/bookmarks/bookmark_client_impl.cc
@@ -4,6 +4,8 @@
 
 #include "ios/chrome/browser/bookmarks/bookmark_client_impl.h"
 
+#include <utility>
+
 #include "base/metrics/user_metrics.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/bookmarks/browser/bookmark_node.h"
@@ -34,20 +36,15 @@
   model_ = model;
 }
 
-bool BookmarkClientImpl::PreferTouchIcon() {
-  return false;
-}
-
 base::CancelableTaskTracker::TaskId
 BookmarkClientImpl::GetFaviconImageForPageURL(
     const GURL& page_url,
-    favicon_base::IconType type,
     favicon_base::FaviconImageCallback callback,
     base::CancelableTaskTracker* tracker) {
   return favicon::GetFaviconImageForPageURL(
       ios::FaviconServiceFactory::GetForBrowserState(
           browser_state_, ServiceAccessType::EXPLICIT_ACCESS),
-      page_url, type, std::move(callback), tracker);
+      page_url, favicon_base::IconType::kFavicon, std::move(callback), tracker);
 }
 
 bool BookmarkClientImpl::SupportsTypedCountForUrls() {
diff --git a/ios/chrome/browser/bookmarks/bookmark_client_impl.h b/ios/chrome/browser/bookmarks/bookmark_client_impl.h
index ce030baf..0f064cb 100644
--- a/ios/chrome/browser/bookmarks/bookmark_client_impl.h
+++ b/ios/chrome/browser/bookmarks/bookmark_client_impl.h
@@ -6,6 +6,7 @@
 #define IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_CLIENT_IMPL_H_
 
 #include <set>
+#include <string>
 #include <vector>
 
 #include "base/deferred_sequenced_task_runner.h"
@@ -34,10 +35,8 @@
 
   // bookmarks::BookmarkClient:
   void Init(bookmarks::BookmarkModel* model) override;
-  bool PreferTouchIcon() override;
   base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
       const GURL& page_url,
-      favicon_base::IconType type,
       favicon_base::FaviconImageCallback callback,
       base::CancelableTaskTracker* tracker) override;
   bool SupportsTypedCountForUrls() override;
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 31521a6..a909e3c 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -584,9 +584,6 @@
      flag_descriptions::kSafeBrowsingRealTimeLookupDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(safe_browsing::kRealTimeUrlLookupEnabled)},
-    {"qr-code-generation", flag_descriptions::kQRCodeGenerationName,
-     flag_descriptions::kQRCodeGenerationDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kQRCodeGeneration)},
     {"autofill-enable-surfacing-server-card-nickname",
      flag_descriptions::kAutofillEnableSurfacingServerCardNicknameName,
      flag_descriptions::kAutofillEnableSurfacingServerCardNicknameDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index abdc73e..3b0fd2b 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -393,10 +393,6 @@
     "Enables pointer support on tablets on iOS 13.4 and above.";
 #endif  // defined(__IPHONE_13_4)
 
-const char kQRCodeGenerationName[] = "QR Code Generation";
-const char kQRCodeGenerationDescription[] =
-    "Allows the generation of a QR code for a page.";
-
 const char kReloadSadTabName[] = "Reload SadTab automatically";
 const char kReloadSadTabDescription[] =
     "When enabled, the first time the renderer crashes, the page is reloaded "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index c98e41b..445fdd68 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -340,10 +340,6 @@
 extern const char kPointerSupportDescription[];
 #endif  // defined(__IPHONE_13_4)
 
-// Title and description for the flag to enable QR code generation for a page.
-extern const char kQRCodeGenerationName[];
-extern const char kQRCodeGenerationDescription[];
-
 // Title and description for the flag that reload the page when the renderer
 // crashes.
 extern const char kReloadSadTabName[];
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm
index 3c78c2b..151b448 100644
--- a/ios/chrome/browser/prerender/preload_controller.mm
+++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -418,6 +418,10 @@
   }
 }
 
+- (UIView*)webViewContainerForWebState:(web::WebState*)webState {
+  return [self.delegate webViewContainer];
+}
+
 #pragma mark - CRWWebStateObserver
 
 - (void)webState:(web::WebState*)webState
diff --git a/ios/chrome/browser/prerender/preload_controller_delegate.h b/ios/chrome/browser/prerender/preload_controller_delegate.h
index 2a8c642..d877005 100644
--- a/ios/chrome/browser/prerender/preload_controller_delegate.h
+++ b/ios/chrome/browser/prerender/preload_controller_delegate.h
@@ -16,6 +16,9 @@
 // This web state will be replaced on successful preload.
 - (web::WebState*)webStateToReplace;
 
+// Returns the UIView used to contain the WebView for sizing purposes.
+- (UIView*)webViewContainer;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_PRERENDER_PRELOAD_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/activity_services/activities/BUILD.gn b/ios/chrome/browser/ui/activity_services/activities/BUILD.gn
index f273a83..8078435d 100644
--- a/ios/chrome/browser/ui/activity_services/activities/BUILD.gn
+++ b/ios/chrome/browser/ui/activity_services/activities/BUILD.gn
@@ -40,7 +40,6 @@
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/policy:feature_flags",
     "//ios/chrome/browser/send_tab_to_self",
-    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/activity_services/data",
     "//ios/chrome/browser/ui/activity_services/requirements",
     "//ios/chrome/browser/ui/commands",
@@ -73,7 +72,6 @@
     "//components/prefs:test_support",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/policy:feature_flags",
-    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/activity_services/data",
     "//ios/chrome/browser/ui/bookmarks:test_support",
     "//ios/chrome/browser/ui/commands",
diff --git a/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity.mm b/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity.mm
index 40bb6c292..58fa0b6 100644
--- a/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity.mm
+++ b/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity.mm
@@ -4,10 +4,8 @@
 
 #import "ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity.h"
 
-#include "base/feature_list.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
@@ -57,7 +55,7 @@
 }
 
 - (BOOL)canPerformWithActivityItems:(NSArray*)activityItems {
-  return base::FeatureList::IsEnabled(kQRCodeGeneration) && self.handler;
+  return self.handler;
 }
 
 + (UIActivityCategory)activityCategory {
diff --git a/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity_unittest.mm b/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity_unittest.mm
index 67d484ec..0118669 100644
--- a/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity_unittest.mm
+++ b/ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity_unittest.mm
@@ -4,10 +4,8 @@
 
 #import "ios/chrome/browser/ui/activity_services/activities/generate_qr_code_activity.h"
 
-#include "base/test/scoped_feature_list.h"
 #import "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
 #include "ios/chrome/browser/ui/commands/qr_generation_commands.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -36,29 +34,18 @@
                                             handler:mocked_handler_];
   }
 
-  base::test::ScopedFeatureList scoped_features_;
   id mocked_handler_;
 };
 
-// Tests that the activity can be performed when the feature flag is on.
-TEST_F(GenerateQrCodeActivityTest, FlagOn_ActivityEnabled) {
-  scoped_features_.InitAndEnableFeature(kQRCodeGeneration);
+// Tests that the activity can be performed when the handler is not nil.
+TEST_F(GenerateQrCodeActivityTest, ValidHandler_ActivityEnabled) {
   GenerateQrCodeActivity* activity = CreateActivity();
 
   EXPECT_TRUE([activity canPerformWithActivityItems:@[]]);
 }
 
-// Tests that the activity cannot be performed when the feature flag is off.
-TEST_F(GenerateQrCodeActivityTest, FlagOff_ActivityDisabled) {
-  scoped_features_.InitAndDisableFeature(kQRCodeGeneration);
-  GenerateQrCodeActivity* activity = CreateActivity();
-
-  EXPECT_FALSE([activity canPerformWithActivityItems:@[]]);
-}
-
 // Tests that the activity cannot be performed when its handler is nil.
 TEST_F(GenerateQrCodeActivityTest, NilHandler_ActivityDisabled) {
-  scoped_features_.InitAndEnableFeature(kQRCodeGeneration);
   GenerateQrCodeActivity* activity =
       [[GenerateQrCodeActivity alloc] initWithURL:GURL("https://example.com")
                                             title:@"Some title"
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_view_controller.mm
index 9c7db5a..a9f7ae7de 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_view_controller.mm
@@ -355,6 +355,10 @@
           constraintEqualToAnchor:self.containerView.leadingAnchor],
       [self.unifiedConsentViewController.view.trailingAnchor
           constraintEqualToAnchor:self.containerView.trailingAnchor],
+      // Constraint between the container view and the horizontal buttons.
+      [self.horizontalButtonsView.topAnchor
+          constraintEqualToAnchor:self.containerView.bottomAnchor
+                         constant:kCompactConstants.ButtonVerticalPadding],
     ]];
     _compactSizeClassConstraints = constraints;
   }
@@ -383,6 +387,10 @@
           constraintEqualToAnchor:self.containerView.centerXAnchor],
       [self.unifiedConsentViewController.view.centerYAnchor
           constraintEqualToAnchor:self.containerView.centerYAnchor],
+      // Constraint between the container view and the horizontal buttons.
+      [self.horizontalButtonsView.topAnchor
+          constraintEqualToAnchor:self.containerView.bottomAnchor
+                         constant:kRegularConstants.ButtonVerticalPadding],
     ]];
     // Adding constraints to ensure the user consent view has a limited size
     // on iPad. If the screen is bigger than the max size, those constraints
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index fe3d60600..025915a5 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -2185,7 +2185,8 @@
       RecordMenuShown(MenuScenario::kBookmarkEntry);
 
       ActionFactory* actionFactory =
-          [[ActionFactory alloc] initWithScenario:MenuScenario::kBookmarkEntry];
+          [[ActionFactory alloc] initWithBrowser:self.browser
+                                        scenario:MenuScenario::kBookmarkEntry];
 
       UIAction* copyAction = [actionFactory actionToCopyURL:node->url()];
 
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index ca4dde2..a3d3675 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -87,6 +87,7 @@
                                   BrowserCoordinatorCommands,
                                   FormInputAccessoryCoordinatorNavigator,
                                   PageInfoCommands,
+                                  PasswordBreachCommands,
                                   RepostFormTabHelperDelegate,
                                   ToolbarAccessoryCoordinatorDelegate,
                                   URLLoadingDelegate,
@@ -226,6 +227,8 @@
                    forProtocol:@protocol(BrowserCoordinatorCommands)];
   [self.dispatcher startDispatchingToTarget:self
                                 forProtocol:@protocol(PageInfoCommands)];
+  [self.dispatcher startDispatchingToTarget:self
+                                forProtocol:@protocol(PasswordBreachCommands)];
   [self installDelegatesForAllWebStates];
   [self installDelegatesForBrowser];
   [self addWebStateListObserver];
@@ -275,6 +278,7 @@
   self.sharingCoordinator = nil;
 
   [self.passwordBreachCoordinator stop];
+  self.passwordBreachCoordinator = nil;
 
   [self.pageInfoCoordinator stop];
 
@@ -360,13 +364,6 @@
       [[PassKitCoordinator alloc] initWithBaseViewController:self.viewController
                                                      browser:self.browser];
 
-  self.passwordBreachCoordinator = [[PasswordBreachCoordinator alloc]
-      initWithBaseViewController:self.viewController
-                         browser:self.browser];
-  [self.browser->GetCommandDispatcher()
-      startDispatchingToTarget:self.passwordBreachCoordinator
-                   forProtocol:@protocol(PasswordBreachCommands)];
-
   self.printController = [[PrintController alloc] init];
   self.printController.baseViewController = self.viewController;
 
@@ -375,6 +372,8 @@
                          browser:self.browser];
   [self.qrScannerCoordinator start];
 
+  /* passwordBreachCoordinator is created and started by a BrowserCommand */
+
   /* ReadingListCoordinator is created and started by a BrowserCommand */
 
   /* RecentTabsCoordinator is created and started by a BrowserCommand */
@@ -434,8 +433,6 @@
   self.passKitCoordinator = nil;
 
   [self.passwordBreachCoordinator stop];
-  [self.browser->GetCommandDispatcher()
-      stopDispatchingToTarget:self.passwordBreachCoordinator];
   self.passwordBreachCoordinator = nil;
 
   self.printController = nil;
@@ -958,4 +955,16 @@
   }
 }
 
+#pragma mark - PasswordBreachCommands
+
+- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType
+                                  URL:(const GURL&)URL {
+  self.passwordBreachCoordinator = [[PasswordBreachCoordinator alloc]
+      initWithBaseViewController:self.viewController
+                         browser:self.browser
+                        leakType:leakType
+                             URL:URL];
+  [self.passwordBreachCoordinator start];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index c54e07c..1a0cc76 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -4465,6 +4465,10 @@
   return self.currentWebState;
 }
 
+- (UIView*)webViewContainer {
+  return self.contentArea;
+}
+
 #pragma mark - NetExportTabHelperDelegate
 
 - (void)netExportTabHelper:(NetExportTabHelper*)tabHelper
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index 37988ac..244509e 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -452,26 +452,37 @@
   [self.NTPMediator locationBarDidResignFirstResponder];
 }
 
-#pragma mark - ThemeChangeDelegate
+#pragma mark - ContentSuggestionsMenuProvider
 
 - (UIContextMenuConfiguration*)contextMenuConfigurationForItem:
     (ContentSuggestionsMostVisitedItem*)item API_AVAILABLE(ios(13.0)) {
-  return [UIContextMenuConfiguration
-      configurationWithIdentifier:nil
-                  previewProvider:nil
-                   actionProvider:^(NSArray<UIMenuElement*>* suggestedActions) {
-                     // Record that this context menu was shown to the user.
-                     RecordMenuShown(MenuScenario::kContentSuggestionsEntry);
+  __weak __typeof(self) weakSelf = self;
 
-                     ActionFactory* actionFactory = [[ActionFactory alloc]
-                         initWithScenario:MenuScenario::
-                                              kContentSuggestionsEntry];
+  UIContextMenuActionProvider actionProvider =
+      ^(NSArray<UIMenuElement*>* suggestedActions) {
+        if (!weakSelf) {
+          // Return an empty menu.
+          return [UIMenu menuWithTitle:@"" children:@[]];
+        }
 
-                     UIAction* copyAction =
-                         [actionFactory actionToCopyURL:item.URL];
+        ContentSuggestionsCoordinator* strongSelf = weakSelf;
 
-                     return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
-                   }];
+        // Record that this context menu was shown to the user.
+        RecordMenuShown(MenuScenario::kContentSuggestionsEntry);
+
+        ActionFactory* actionFactory = [[ActionFactory alloc]
+            initWithBrowser:strongSelf.browser
+                   scenario:MenuScenario::kContentSuggestionsEntry];
+
+        UIAction* copyAction = [actionFactory actionToCopyURL:item.URL];
+
+        return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
+      };
+
+  return
+      [UIContextMenuConfiguration configurationWithIdentifier:nil
+                                              previewProvider:nil
+                                               actionProvider:actionProvider];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index cf157bae..2ab28b7 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -620,6 +620,7 @@
       [self.collectionViewModel itemAtIndexPath:indexPath];
   return ![self.collectionUpdater isMostVisitedSection:indexPath.section] &&
          ![self.collectionUpdater isPromoSection:indexPath.section] &&
+         ![self.collectionUpdater isDiscoverSection:indexPath.section] &&
          [self.collectionUpdater contentSuggestionTypeForItem:item] !=
              ContentSuggestionTypeLearnMore &&
          [self.collectionUpdater contentSuggestionTypeForItem:item] !=
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
index 1742ec3..21695f9 100644
--- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
+++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
@@ -586,6 +586,7 @@
   self.TOSTextView.editable = NO;
   self.TOSTextView.adjustsFontForContentSizeCategory = YES;
   self.TOSTextView.delegate = self;
+  self.TOSTextView.backgroundColor = UIColor.clearColor;
   self.TOSTextView.linkTextAttributes =
       @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]};
 
@@ -609,6 +610,7 @@
   NSMutableAttributedString* attributedText =
       [[NSMutableAttributedString alloc] initWithString:TOSText];
   [attributedText addAttributes:@{
+    NSForegroundColorAttributeName : [UIColor colorNamed:kTextPrimaryColor],
     NSParagraphStyleAttributeName : style,
     NSFontAttributeName : font
   }
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 249a099..a74ef1b 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -27,10 +27,12 @@
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
+    "//ios/chrome/browser/ui/history/public",
     "//ios/chrome/browser/ui/menu",
     "//ios/chrome/browser/ui/table_view",
     "//ios/chrome/browser/ui/table_view:feature_flags",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/util:multiwindow_util",
   ]
   frameworks = [
     "MobileCoreServices.framework",
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm
index 51b9be0..353618b 100644
--- a/ios/chrome/browser/ui/history/history_coordinator.mm
+++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -18,10 +18,12 @@
 #import "ios/chrome/browser/ui/history/history_transitioning_delegate.h"
 #include "ios/chrome/browser/ui/history/history_ui_delegate.h"
 #include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
+#import "ios/chrome/browser/ui/history/public/history_presentation_delegate.h"
 #import "ios/chrome/browser/ui/menu/action_factory.h"
 #import "ios/chrome/browser/ui/menu/menu_histograms.h"
 #import "ios/chrome/browser/ui/table_view/feature_flags.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
+#import "ios/chrome/browser/ui/util/multi_window_support.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -54,12 +56,6 @@
 @end
 
 @implementation HistoryCoordinator
-@synthesize historyClearBrowsingDataCoordinator =
-    _historyClearBrowsingDataCoordinator;
-@synthesize historyNavigationController = _historyNavigationController;
-@synthesize historyTransitioningDelegate = _historyTransitioningDelegate;
-@synthesize mediator = _mediator;
-@synthesize presentationDelegate = _presentationDelegate;
 
 - (void)start {
   // Initialize and configure HistoryTableViewController.
@@ -181,24 +177,61 @@
     API_AVAILABLE(ios(13.0)) {
   __weak id<HistoryEntryItemDelegate> historyItemDelegate =
       self.historyTableViewController;
+  __weak __typeof(self) weakSelf = self;
 
-  UIContextMenuActionProvider actionProvider =
-      ^(NSArray<UIMenuElement*>* suggestedActions) {
-        // Record that this context menu was shown to the user.
-        RecordMenuShown(MenuScenario::kHistoryEntry);
+  UIContextMenuActionProvider actionProvider = ^(
+      NSArray<UIMenuElement*>* suggestedActions) {
+    if (!weakSelf) {
+      // Return an empty menu.
+      return [UIMenu menuWithTitle:@"" children:@[]];
+    }
 
-        ActionFactory* actionFactory = [[ActionFactory alloc]
-            initWithScenario:MenuScenario::kHistoryEntry];
+    HistoryCoordinator* strongSelf = weakSelf;
 
-        UIAction* copyAction = [actionFactory actionToCopyURL:item.URL];
+    // Record that this context menu was shown to the user.
+    RecordMenuShown(MenuScenario::kHistoryEntry);
 
-        UIAction* deleteAction = [actionFactory actionToDeleteWithBlock:^{
-          [historyItemDelegate historyEntryItemDidRequestDelete:item];
-        }];
+    ActionFactory* actionFactory =
+        [[ActionFactory alloc] initWithBrowser:strongSelf.browser
+                                      scenario:MenuScenario::kHistoryEntry];
 
-        return [UIMenu menuWithTitle:@""
-                            children:@[ copyAction, deleteAction ]];
-      };
+    NSMutableArray<UIMenuElement*>* menuElements =
+        [[NSMutableArray alloc] init];
+
+    // Copy URL action.
+    [menuElements addObject:[actionFactory actionToCopyURL:item.URL]];
+
+    // "Open in" actions.
+    [menuElements
+        addObject:[actionFactory
+                      actionToOpenInNewTabWithURL:item.URL
+                                       completion:^{
+                                         [weakSelf onOpenedURLInNewTab];
+                                       }]];
+    [menuElements
+        addObject:
+            [actionFactory
+                actionToOpenInNewIncognitoTabWithURL:item.URL
+                                          completion:^{
+                                            [weakSelf
+                                                onOpenedURLInNewIncognitoTab];
+                                          }]];
+    if (IsMultipleScenesSupported()) {
+      [menuElements
+          addObject:
+              [actionFactory
+                  actionToOpenInNewWindowWithURL:item.URL
+                                  activityOrigin:WindowActivityHistoryOrigin
+                                      completion:nil]];
+    }
+
+    // Delete action.
+    [menuElements addObject:[actionFactory actionToDeleteWithBlock:^{
+                    [historyItemDelegate historyEntryItemDidRequestDelete:item];
+                  }]];
+
+    return [UIMenu menuWithTitle:@"" children:menuElements];
+  };
 
   return
       [UIContextMenuConfiguration configurationWithIdentifier:nil
@@ -206,4 +239,24 @@
                                                actionProvider:actionProvider];
 }
 
+#pragma mark - Private
+
+// Stops the coordinator and requests the presentation delegate to transition to
+// the active regular tab.
+- (void)onOpenedURLInNewTab {
+  __weak __typeof(self) weakSelf = self;
+  [self stopWithCompletion:^{
+    [weakSelf.presentationDelegate showActiveRegularTabFromHistory];
+  }];
+}
+
+// Stops the coordinator and requests the presentation delegate to transition to
+// the active incognito tab.
+- (void)onOpenedURLInNewIncognitoTab {
+  __weak __typeof(self) weakSelf = self;
+  [self stopWithCompletion:^{
+    [weakSelf.presentationDelegate showActiveIncognitoTabFromHistory];
+  }];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/menu/BUILD.gn b/ios/chrome/browser/ui/menu/BUILD.gn
index cd543865..b1549bb 100644
--- a/ios/chrome/browser/ui/menu/BUILD.gn
+++ b/ios/chrome/browser/ui/menu/BUILD.gn
@@ -14,7 +14,10 @@
   deps = [
     "//base",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/url_loading",
+    "//ios/chrome/browser/window_activities",
     "//net",
     "//ui/base",
     "//url",
@@ -33,6 +36,8 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/main:test_support",
+    "//ios/chrome/browser/sessions:test_support",
+    "//ios/chrome/browser/ui/commands",
     "//ios/web/public/test",
     "//testing/gtest",
     "//third_party/ocmock",
diff --git a/ios/chrome/browser/ui/menu/action_factory.h b/ios/chrome/browser/ui/menu/action_factory.h
index 0f2b1e5..85dd03b 100644
--- a/ios/chrome/browser/ui/menu/action_factory.h
+++ b/ios/chrome/browser/ui/menu/action_factory.h
@@ -10,7 +10,9 @@
 #import "base/ios/block_types.h"
 #import "ios/chrome/browser/ui/menu/menu_action_type.h"
 #import "ios/chrome/browser/ui/menu/menu_histograms.h"
+#import "ios/chrome/browser/window_activities/window_activity_helpers.h"
 
+class Browser;
 class GURL;
 
 // Factory providing methods to create UIActions with consistent titles, images
@@ -18,9 +20,10 @@
 API_AVAILABLE(ios(13.0))
 @interface ActionFactory : NSObject
 
-// Initializes a factory instance to create action instances for the given
-// |scenario|.
-- (instancetype)initWithScenario:(MenuScenario)scenario;
+// Initializes a factory instance for the current |browser| to create action
+// instances for the given |scenario|.
+- (instancetype)initWithBrowser:(Browser*)browser
+                       scenario:(MenuScenario)scenario;
 
 // Creates a UIAction instance configured with the given |title| and |image|.
 // Upon execution, the action's |type| will be recorded and the |block| will be
@@ -35,9 +38,27 @@
 - (UIAction*)actionToCopyURL:(const GURL)URL;
 
 // Creates a UIAction instance configured for deletion which will invoke
-// the given |block| upon being triggered.
+// the given delete |block| when executed.
 - (UIAction*)actionToDeleteWithBlock:(ProceduralBlock)block;
 
+// Creates a UIAction instance configured for opening the |URL| in a new tab and
+// which will invoke the given |completion| block after execution.
+- (UIAction*)actionToOpenInNewTabWithURL:(const GURL)URL
+                              completion:(ProceduralBlock)completion;
+
+// Creates a UIAction instance configured for opening the |URL| in a new
+// incognito tab and which will invoke the given |completion| block after
+// execution.
+- (UIAction*)actionToOpenInNewIncognitoTabWithURL:(const GURL)URL
+                                       completion:(ProceduralBlock)completion;
+
+// Creates a UIAction instance configured for opening the |URL| in a new window
+// from |activityOrigin|, and which will invoke the given |completion| block
+// after execution.
+- (UIAction*)actionToOpenInNewWindowWithURL:(const GURL)URL
+                             activityOrigin:(WindowActivityOrigin)activityOrigin
+                                 completion:(ProceduralBlock)completion;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_ACTION_FACTORY_H_
diff --git a/ios/chrome/browser/ui/menu/action_factory.mm b/ios/chrome/browser/ui/menu/action_factory.mm
index 9c9ae49..8b484d0d 100644
--- a/ios/chrome/browser/ui/menu/action_factory.mm
+++ b/ios/chrome/browser/ui/menu/action_factory.mm
@@ -5,7 +5,11 @@
 #import "ios/chrome/browser/ui/menu/action_factory.h"
 
 #import "base/metrics/histogram_functions.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/util/pasteboard_util.h"
+#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
+#import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 #import "url/gurl.h"
@@ -16,14 +20,22 @@
 
 @interface ActionFactory ()
 
+// Current browser instance.
+@property(nonatomic, assign) Browser* browser;
+
+// Histogram to record executed actions.
 @property(nonatomic, assign) const char* histogram;
 
 @end
 
 @implementation ActionFactory
 
-- (instancetype)initWithScenario:(MenuScenario)scenario {
+- (instancetype)initWithBrowser:(Browser*)browser
+                       scenario:(MenuScenario)scenario {
+  DCHECK(browser);
+
   if (self = [super init]) {
+    _browser = browser;
     _histogram = GetActionsHistogramName(scenario);
   }
   return self;
@@ -65,4 +77,58 @@
   return action;
 }
 
+- (UIAction*)actionToOpenInNewTabWithURL:(const GURL)URL
+                              completion:(ProceduralBlock)completion {
+  UrlLoadParams params = UrlLoadParams::InNewTab(URL);
+  UrlLoadingBrowserAgent* loadingAgent =
+      UrlLoadingBrowserAgent::FromBrowser(self.browser);
+  return [self actionWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
+                         image:[UIImage systemImageNamed:@"plus"]
+                          type:MenuActionType::OpenInNewTab
+                         block:^{
+                           loadingAgent->Load(params);
+                           if (completion) {
+                             completion();
+                           }
+                         }];
+}
+
+- (UIAction*)actionToOpenInNewIncognitoTabWithURL:(const GURL)URL
+                                       completion:(ProceduralBlock)completion {
+  UrlLoadParams params = UrlLoadParams::InNewTab(URL);
+  params.in_incognito = YES;
+  UrlLoadingBrowserAgent* loadingAgent =
+      UrlLoadingBrowserAgent::FromBrowser(self.browser);
+  return
+      [self actionWithTitle:l10n_util::GetNSString(
+                                IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
+                      image:nil
+                       type:MenuActionType::OpenInNewIncognitoTab
+                      block:^{
+                        loadingAgent->Load(params);
+                        if (completion) {
+                          completion();
+                        }
+                      }];
+}
+
+- (UIAction*)actionToOpenInNewWindowWithURL:(const GURL)URL
+                             activityOrigin:(WindowActivityOrigin)activityOrigin
+                                 completion:(ProceduralBlock)completion {
+  id<ApplicationCommands> windowOpener = HandlerForProtocol(
+      self.browser->GetCommandDispatcher(), ApplicationCommands);
+  NSUserActivity* activity = ActivityToLoadURL(activityOrigin, URL);
+  return [self actionWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_CONTENT_CONTEXT_OPENINNEWWINDOW)
+                         image:[UIImage systemImageNamed:@"plus.square"]
+                          type:MenuActionType::OpenInNewWindow
+                         block:^{
+                           [windowOpener openNewWindowWithActivity:activity];
+                           if (completion) {
+                             completion();
+                           }
+                         }];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/menu/action_factory_unittest.mm b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
index eea0012..3371c406 100644
--- a/ios/chrome/browser/ui/menu/action_factory_unittest.mm
+++ b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
@@ -5,11 +5,14 @@
 #import "ios/chrome/browser/ui/menu/action_factory.h"
 
 #import "base/test/metrics/histogram_tester.h"
+#import "base/test/task_environment.h"
 #import "ios/chrome/browser/main/test_browser.h"
+#import "ios/chrome/browser/sessions/test_session_service.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/menu/menu_action_type.h"
 #import "ios/chrome/browser/ui/menu/menu_histograms.h"
 #import "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/test/web_task_environment.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -33,7 +36,23 @@
 // Test fixture for the ActionFactory.
 class ActionFactoryTest : public PlatformTest {
  protected:
-  ActionFactoryTest() : test_title_(@"SomeTitle") {}
+  ActionFactoryTest()
+      : test_title_(@"SomeTitle"),
+        test_browser_(std::make_unique<TestBrowser>()) {}
+
+  void SetUp() override {
+    mock_application_commands_handler_ =
+        OCMStrictProtocolMock(@protocol(ApplicationCommands));
+    [test_browser_->GetCommandDispatcher()
+        startDispatchingToTarget:mock_application_commands_handler_
+                     forProtocol:@protocol(ApplicationCommands)];
+
+    mock_application_settings_commands_handler_ =
+        OCMStrictProtocolMock(@protocol(ApplicationSettingsCommands));
+    [test_browser_->GetCommandDispatcher()
+        startDispatchingToTarget:mock_application_settings_commands_handler_
+                     forProtocol:@protocol(ApplicationSettingsCommands)];
+  }
 
   // Creates a blue square.
   UIImage* CreateMockImage() {
@@ -41,9 +60,12 @@
         CGSizeMake(10, 10), [UIColor blueColor]);
   }
 
-  web::WebTaskEnvironment task_environment_;
+  base::test::TaskEnvironment task_environment_;
   base::HistogramTester histogram_tester_;
   NSString* test_title_;
+  std::unique_ptr<TestBrowser> test_browser_;
+  id mock_application_commands_handler_;
+  id mock_application_settings_commands_handler_;
 };
 
 // Tests the creation of an action using the parameterized method, and verifies
@@ -51,7 +73,8 @@
 TEST_F(ActionFactoryTest, CreateActionWithParameters) {
   if (@available(iOS 13.0, *)) {
     ActionFactory* factory =
-        [[ActionFactory alloc] initWithScenario:kTestMenuScenario];
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
 
     UIImage* mockImage = CreateMockImage();
 
@@ -70,7 +93,8 @@
 TEST_F(ActionFactoryTest, CopyAction) {
   if (@available(iOS 13.0, *)) {
     ActionFactory* factory =
-        [[ActionFactory alloc] initWithScenario:kTestMenuScenario];
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
 
     UIImage* expectedImage = [UIImage systemImageNamed:@"doc.on.doc"];
     NSString* expectedTitle = l10n_util::GetNSString(IDS_IOS_COPY_ACTION_TITLE);
@@ -88,7 +112,8 @@
 TEST_F(ActionFactoryTest, DeleteAction) {
   if (@available(iOS 13.0, *)) {
     ActionFactory* factory =
-        [[ActionFactory alloc] initWithScenario:kTestMenuScenario];
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
 
     UIImage* expectedImage = [UIImage systemImageNamed:@"trash"];
     NSString* expectedTitle =
@@ -102,4 +127,69 @@
   }
 }
 
+// Tests that the Open in New Tab action has the right title and image.
+TEST_F(ActionFactoryTest, OpenInNewTabAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    GURL testURL = GURL("https://example.com");
+
+    UIImage* expectedImage = [UIImage systemImageNamed:@"plus"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
+
+    UIAction* action = [factory actionToOpenInNewTabWithURL:testURL
+                                                 completion:nil];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
+// Tests that the Open in New Incognito Tab action has the right title and
+// image.
+TEST_F(ActionFactoryTest, OpenInNewIncognitoTabAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    GURL testURL = GURL("https://example.com");
+
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
+
+    UIAction* action = [factory actionToOpenInNewIncognitoTabWithURL:testURL
+                                                          completion:nil];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_FALSE(!!action.image);
+  }
+}
+
+// Tests that the Open in New Window action has the right title and image.
+TEST_F(ActionFactoryTest, OpenInNewWindowAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    GURL testURL = GURL("https://example.com");
+
+    UIImage* expectedImage = [UIImage systemImageNamed:@"plus.square"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENINNEWWINDOW);
+
+    UIAction* action =
+        [factory actionToOpenInNewWindowWithURL:testURL
+                                 activityOrigin:WindowActivityToolsOrigin
+                                     completion:nil];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
 #endif  // defined(__IPHONE_13_0)
diff --git a/ios/chrome/browser/ui/menu/menu_action_type.h b/ios/chrome/browser/ui/menu/menu_action_type.h
index 641f752..82f0e84 100644
--- a/ios/chrome/browser/ui/menu/menu_action_type.h
+++ b/ios/chrome/browser/ui/menu/menu_action_type.h
@@ -8,6 +8,13 @@
 // Enum representing the existing set of menu actions as types. Current values
 // should not be renumbered. Please keep in sync with "IOSMenuAction" in
 // src/tools/metrics/histograms/enums.xml.
-enum class MenuActionType { Copy = 0, Delete = 1, kMaxValue = Delete };
+enum class MenuActionType {
+  Copy = 0,
+  Delete = 1,
+  OpenInNewTab = 2,
+  OpenInNewIncognitoTab = 3,
+  OpenInNewWindow = 4,
+  kMaxValue = OpenInNewWindow
+};
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_MENU_ACTION_TYPE_H_
diff --git a/ios/chrome/browser/ui/passwords/password_breach_coordinator.h b/ios/chrome/browser/ui/passwords/password_breach_coordinator.h
index bca6ae2..729694f 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_coordinator.h
+++ b/ios/chrome/browser/ui/passwords/password_breach_coordinator.h
@@ -5,13 +5,25 @@
 #ifndef IOS_CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BREACH_COORDINATOR_H_
 #define IOS_CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BREACH_COORDINATOR_H_
 
+#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 
+class GURL;
+
 // Presents and stops the Password Breach feature, which consists in alerting
 // the user that Chrome detected a leaked credential. In some scenarios it
 // prompts for a checkup of the stored passwords.
 @interface PasswordBreachCoordinator : ChromeCoordinator
 
+- (instancetype)
+    initWithBaseViewController:(UIViewController*)baseViewController
+                       browser:(Browser*)browser
+                      leakType:(password_manager::CredentialLeakType)leakType
+                           URL:(const GURL&)URL NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithBaseViewController:(UIViewController*)viewController
+                                   browser:(Browser*)browser NS_UNAVAILABLE;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BREACH_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm b/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
index c501872..c1ba3b9 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
@@ -14,13 +14,15 @@
 #import "ios/chrome/browser/ui/passwords/password_breach_view_controller.h"
 #import "ios/chrome/common/ui/elements/popover_label_view_controller.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@interface PasswordBreachCoordinator () <PasswordBreachCommands,
-                                         PasswordBreachPresenter>
+using password_manager::CredentialLeakType;
+
+@interface PasswordBreachCoordinator () <PasswordBreachPresenter>
 
 // Main view controller for this coordinator.
 @property(nonatomic, strong) PasswordBreachViewController* viewController;
@@ -32,15 +34,44 @@
 // Main mediator for this coordinator.
 @property(nonatomic, strong) PasswordBreachMediator* mediator;
 
+// Leak type of the dialog.
+@property(nonatomic, assign) CredentialLeakType leakType;
+
+// Url needed for the dialog.
+@property(nonatomic, assign) GURL url;
+
 @end
 
 @implementation PasswordBreachCoordinator
 
+- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
+                                   browser:(Browser*)browser
+                                  leakType:(CredentialLeakType)leakType
+                                       URL:(const GURL&)URL {
+  self = [super initWithBaseViewController:baseViewController browser:browser];
+  if (self) {
+    _url = URL;
+    _leakType = leakType;
+  }
+  return self;
+}
+
 - (void)start {
-  [super start];
-  // To start, a mediator and view controller should be ready.
-  DCHECK(self.viewController);
-  DCHECK(self.mediator);
+  self.viewController = [[PasswordBreachViewController alloc] init];
+  self.viewController.modalPresentationStyle = UIModalPresentationFormSheet;
+  if (@available(iOS 13, *)) {
+    self.viewController.modalInPresentation = YES;
+  }
+  id<ApplicationCommands> handler = HandlerForProtocol(
+      self.browser->GetCommandDispatcher(), ApplicationCommands);
+  self.mediator =
+      [[PasswordBreachMediator alloc] initWithConsumer:self.viewController
+                                             presenter:self
+                                               handler:handler
+                                                   URL:_url
+                                              leakType:self.leakType];
+  self.viewController.actionHandler = self.mediator;
+
   [self.baseViewController presentViewController:self.viewController
                                         animated:YES
                                       completion:nil];
@@ -56,28 +87,6 @@
   [super stop];
 }
 
-#pragma mark - PasswordBreachCommands
-
-- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType
-                                  URL:(const GURL&)URL {
-  DCHECK(self.browser);
-  self.viewController = [[PasswordBreachViewController alloc] init];
-  self.viewController.modalPresentationStyle = UIModalPresentationFormSheet;
-  if (@available(iOS 13, *)) {
-    self.viewController.modalInPresentation = YES;
-  }
-  id<ApplicationCommands> handler = HandlerForProtocol(
-      self.browser->GetCommandDispatcher(), ApplicationCommands);
-  self.mediator =
-      [[PasswordBreachMediator alloc] initWithConsumer:self.viewController
-                                             presenter:self
-                                               handler:handler
-                                                   URL:URL
-                                              leakType:leakType];
-  self.viewController.actionHandler = self.mediator;
-  [self start];
-}
-
 #pragma mark - PasswordBreachPresenter
 
 - (void)presentLearnMore {
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
index 5d03470..52f1940f 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
@@ -420,21 +420,33 @@
 
 - (UIContextMenuConfiguration*)contextMenuConfigurationForItem:
     (id<ReadingListListItem>)item API_AVAILABLE(ios(13.0)) {
-  return [UIContextMenuConfiguration
-      configurationWithIdentifier:nil
-                  previewProvider:nil
-                   actionProvider:^(NSArray<UIMenuElement*>* suggestedActions) {
-                     // Record that this context menu was shown to the user.
-                     RecordMenuShown(MenuScenario::kReadingListEntry);
+  __weak __typeof(self) weakSelf = self;
 
-                     ActionFactory* actionFactory = [[ActionFactory alloc]
-                         initWithScenario:MenuScenario::kReadingListEntry];
+  UIContextMenuActionProvider actionProvider =
+      ^(NSArray<UIMenuElement*>* suggestedActions) {
+        if (!weakSelf) {
+          // Return an empty menu.
+          return [UIMenu menuWithTitle:@"" children:@[]];
+        }
 
-                     UIAction* copyAction =
-                         [actionFactory actionToCopyURL:item.entryURL];
+        ReadingListCoordinator* strongSelf = weakSelf;
 
-                     return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
-                   }];
+        // Record that this context menu was shown to the user.
+        RecordMenuShown(MenuScenario::kReadingListEntry);
+
+        ActionFactory* actionFactory = [[ActionFactory alloc]
+            initWithBrowser:strongSelf.browser
+                   scenario:MenuScenario::kReadingListEntry];
+
+        UIAction* copyAction = [actionFactory actionToCopyURL:item.entryURL];
+
+        return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
+      };
+
+  return
+      [UIContextMenuConfiguration configurationWithIdentifier:nil
+                                              previewProvider:nil
+                                               actionProvider:actionProvider];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 5271048..e4bf98e 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -176,21 +176,33 @@
 
 - (UIContextMenuConfiguration*)contextMenuConfigurationForItem:
     (TableViewURLItem*)item API_AVAILABLE(ios(13.0)) {
-  return [UIContextMenuConfiguration
-      configurationWithIdentifier:nil
-                  previewProvider:nil
-                   actionProvider:^(NSArray<UIMenuElement*>* suggestedActions) {
-                     // Record that this context menu was shown to the user.
-                     RecordMenuShown(MenuScenario::kRecentTabsEntry);
+  __weak __typeof(self) weakSelf = self;
 
-                     ActionFactory* actionFactory = [[ActionFactory alloc]
-                         initWithScenario:MenuScenario::kRecentTabsEntry];
+  UIContextMenuActionProvider actionProvider =
+      ^(NSArray<UIMenuElement*>* suggestedActions) {
+        if (!weakSelf) {
+          // Return an empty menu.
+          return [UIMenu menuWithTitle:@"" children:@[]];
+        }
 
-                     UIAction* copyAction =
-                         [actionFactory actionToCopyURL:item.URL];
+        RecentTabsCoordinator* strongSelf = weakSelf;
 
-                     return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
-                   }];
+        // Record that this context menu was shown to the user.
+        RecordMenuShown(MenuScenario::kRecentTabsEntry);
+
+        ActionFactory* actionFactory = [[ActionFactory alloc]
+            initWithBrowser:strongSelf.browser
+                   scenario:MenuScenario::kRecentTabsEntry];
+
+        UIAction* copyAction = [actionFactory actionToCopyURL:item.URL];
+
+        return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
+      };
+
+  return
+      [UIContextMenuConfiguration configurationWithIdentifier:nil
+                                              previewProvider:nil
+                                               actionProvider:actionProvider];
 }
 
 - (UIContextMenuConfiguration*)
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
index 3f9b81d..fad7a89d 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -442,11 +442,15 @@
           password_manager::features::kPasswordCheck)) {
     // Password check.
     [model addSectionWithIdentifier:SectionIdentifierPasswordCheck];
-    _passwordProblemsItem = [self passwordProblemsItem];
+    if (!_passwordProblemsItem) {
+      _passwordProblemsItem = [self passwordProblemsItem];
+    }
 
     [model addItem:_passwordProblemsItem
         toSectionWithIdentifier:SectionIdentifierPasswordCheck];
-    _checkForProblemsItem = [self checkForProblemsItem];
+    if (!_checkForProblemsItem) {
+      _checkForProblemsItem = [self checkForProblemsItem];
+    }
 
     [model addItem:_checkForProblemsItem
         toSectionWithIdentifier:SectionIdentifierPasswordCheck];
@@ -832,7 +836,7 @@
   [self searchForTerm:searchText];
 }
 
-#pragma mark - PasswordIssuesViewControllerDelegate
+#pragma mark - PasswordIssuesCoordinatorDelegate
 
 - (void)passwordIssuesCoordinatorDidRemove:
     (PasswordIssuesCoordinator*)coordinator {
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
index cc8f79b..f84dcb12 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
@@ -26,6 +26,7 @@
 #include "ios/chrome/browser/passwords/save_passwords_consumer.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_check_item.h"
 #import "ios/chrome/browser/ui/settings/password/password_details_table_view_controller.h"
+#import "ios/chrome/browser/ui/settings/password/password_issues_coordinator.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_consumer.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h"
@@ -54,8 +55,10 @@
 
 // Declaration to conformance to SavePasswordsConsumerDelegate and keep tests in
 // this file working.
-@interface PasswordsTableViewController (Test) <UISearchBarDelegate,
-                                                PasswordsConsumer>
+@interface PasswordsTableViewController (Test) <
+    UISearchBarDelegate,
+    PasswordIssuesCoordinatorDelegate,
+    PasswordsConsumer>
 - (void)updateExportPasswordsButton;
 @end
 
@@ -760,6 +763,23 @@
   EXPECT_EQ(2, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
 }
 
+// Test verifies Passwords View Controller handles deletion of passwords.
+TEST_P(PasswordsTableViewControllerTest, PasswordIssuesDeletion) {
+  if (!GetParam().password_check_enabled)
+    return;
+  AddSavedForm1();
+  AddSavedForm2();
+  EXPECT_EQ(2, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
+
+  PasswordsTableViewController* passwords_controller =
+      static_cast<PasswordsTableViewController*>(controller());
+
+  auto password =
+      GetTestStore().stored_passwords().at("http://www.example.com/").at(0);
+  EXPECT_TRUE([passwords_controller willHandlePasswordDeletion:password]);
+  EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
+}
+
 const std::vector<PasswordCheckFeatureStatus> kPasswordCheckFeatureStatusCases{
     // Password check disabled
     {FALSE},
diff --git a/ios/chrome/browser/ui/sharing/BUILD.gn b/ios/chrome/browser/ui/sharing/BUILD.gn
index a3e0b07..2c23fdf 100644
--- a/ios/chrome/browser/ui/sharing/BUILD.gn
+++ b/ios/chrome/browser/ui/sharing/BUILD.gn
@@ -10,7 +10,6 @@
   ]
   deps = [
     "//base",
-    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/activity_services",
     "//ios/chrome/browser/ui/activity_services/requirements",
     "//ios/chrome/browser/ui/commands",
@@ -30,7 +29,6 @@
     "//base/test:test_support",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/main:test_support",
-    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/activity_services",
     "//ios/chrome/browser/ui/activity_services/requirements",
     "//ios/chrome/browser/ui/commands",
diff --git a/ios/chrome/browser/ui/sharing/sharing_coordinator.mm b/ios/chrome/browser/ui/sharing/sharing_coordinator.mm
index ad08719..fc6d1c6 100644
--- a/ios/chrome/browser/ui/sharing/sharing_coordinator.mm
+++ b/ios/chrome/browser/ui/sharing/sharing_coordinator.mm
@@ -4,14 +4,12 @@
 
 #import "ios/chrome/browser/ui/sharing/sharing_coordinator.h"
 
-#include "base/feature_list.h"
 #import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
 #import "ios/chrome/browser/ui/activity_services/activity_service_coordinator.h"
 #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
 #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_presentation.h"
 #import "ios/chrome/browser/ui/commands/qr_generation_commands.h"
 #import "ios/chrome/browser/ui/qr_generator/qr_generator_coordinator.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -80,7 +78,6 @@
 #pragma mark - QRGenerationCommands
 
 - (void)generateQRCode:(GenerateQRCodeCommand*)command {
-  DCHECK(base::FeatureList::IsEnabled(kQRCodeGeneration));
   self.qrGeneratorCoordinator = [[QRGeneratorCoordinator alloc]
       initWithBaseViewController:self.baseViewController
                          browser:self.browser
diff --git a/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm b/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
index d845918..65a40825 100644
--- a/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/sharing/sharing_coordinator_unittest.mm
@@ -6,7 +6,6 @@
 
 #import <UIKit/UIKit.h>
 
-#include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/main/test_browser.h"
@@ -15,7 +14,6 @@
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/commands/generate_qr_code_command.h"
 #import "ios/chrome/browser/ui/commands/qr_generation_commands.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/chrome/test/scoped_key_window.h"
@@ -69,7 +67,6 @@
   }
 
   web::WebTaskEnvironment task_environment_;
-  base::test::ScopedFeatureList scoped_features_;
   ScopedKeyWindow scoped_key_window_;
   UIViewController* base_view_controller_;
   std::unique_ptr<TestBrowser> browser_;
@@ -135,7 +132,6 @@
 
 // Tests that the coordinator handles the QRGenerationCommands protocol.
 TEST_F(SharingCoordinatorTest, GenerateQRCode) {
-  scoped_features_.InitAndEnableFeature(kQRCodeGeneration);
   SharingCoordinator* coordinator = GetCoordinator();
 
   id vc_partial_mock = OCMPartialMock(base_view_controller_);
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index b588f1e..99bce04 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -37,9 +37,6 @@
 const base::Feature kFirstResponderSendAction{
     "FirstResponderSendAction", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kQRCodeGeneration{"QRCodeGeneration",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kEnableNativeContextMenus{
     "EnableNativeContextMenus", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
index 0e3a27897..cb5a81bf 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.h
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -41,9 +41,6 @@
 // Verify if the crash in https://crbug.com/816427 is fixed on iOS 12.
 extern const base::Feature kFirstResponderSendAction;
 
-// Feature flag to enable QR code generation for a URL.
-extern const base::Feature kQRCodeGeneration;
-
 // Feature flag that enables the native UI Context Menus (not for Web content).
 extern const base::Feature kEnableNativeContextMenus;
 
diff --git a/media/gpu/test/video_frame_validator.cc b/media/gpu/test/video_frame_validator.cc
index 9f6a502..5014f88 100644
--- a/media/gpu/test/video_frame_validator.cc
+++ b/media/gpu/test/video_frame_validator.cc
@@ -240,7 +240,23 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(validator_thread_sequence_checker_);
   base::MD5Context context;
   base::MD5Init(&context);
-  VideoFrame::HashFrameForTesting(&context, video_frame);
+
+  // VideoFrame::HashFrameForTesting() computes MD5 hash values of the coded
+  // area. However, MD5 hash values used in our test only use the visible area
+  // because they are computed from images output by decode tools like ffmpeg.
+  const VideoPixelFormat format = video_frame.format();
+  const gfx::Rect& visible_rect = video_frame.visible_rect();
+  for (size_t i = 0; i < VideoFrame::NumPlanes(format); ++i) {
+    const int visible_row_bytes =
+        VideoFrame::RowBytes(i, format, visible_rect.width());
+    const int visible_rows = VideoFrame::Rows(i, format, visible_rect.height());
+    const char* data = reinterpret_cast<const char*>(video_frame.data(i));
+    const size_t stride = video_frame.stride(i);
+    for (int row = 0; row < visible_rows; ++row) {
+      base::MD5Update(&context, base::StringPiece(data + (stride * row),
+                                                  visible_row_bytes));
+    }
+  }
   base::MD5Digest digest;
   base::MD5Final(&digest, &context);
   return MD5DigestToBase16(digest);
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b2a71d9..0002bca3 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5686,21 +5686,6 @@
             ]
         }
     ],
-    "QRCodeGenerationStudy": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "QRCodeGeneration"
-                    ]
-                }
-            ]
-        }
-    ],
     "QRCodeGeneratorDesktopStudy": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/devtools/inspector_issue.mojom b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
index b1ec5b05..bc216a49 100644
--- a/third_party/blink/public/mojom/devtools/inspector_issue.mojom
+++ b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
@@ -7,6 +7,7 @@
 import "url/mojom/url.mojom";
 import "services/network/public/mojom/cookie_manager.mojom";
 import "services/network/public/mojom/blocked_by_response_reason.mojom";
+import "services/network/public/mojom/source_location.mojom";
 import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
 
 // A code that uniquely identifies an issue. This type should be descriptive
@@ -80,13 +81,7 @@
   string violated_directive;
   ContentSecurityPolicyViolationType content_security_policy_violation_type;
   AffectedFrame? frame_ancestor;
-  SourceCodeLocation? source_code_location;
-};
-
-struct SourceCodeLocation {
-  string url;
-  uint32 line_number;
-  uint32 column_number;
+  network.mojom.SourceLocation? source_location;
 };
 
 enum SameSiteCookieOperation {
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py b/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
index ee49eb5..f89dd7f4 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
@@ -405,9 +405,11 @@
         assignment_value = "{}()".format(type_info.value_t)
     elif default_value.idl_type.is_object:
         dict_name = blink_class_name(idl_type.unwrap().type_definition_object)
-        value = _format("{}::Create()", dict_name)
+        value = _format("{}::Create(${isolate})", dict_name)
         initializer_expr = value
+        initializer_deps = ["isolate"]
         assignment_value = value
+        assignment_deps = ["isolate"]
     elif default_value.idl_type.is_boolean:
         value = "true" if default_value.value else "false"
         initializer_expr = value
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index a27547a5..cc15b1b 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1441,12 +1441,12 @@
     cspDetails->frame_ancestor = std::move(affected_frame);
   }
   if (violation_data.sourceFile() && violation_data.lineNumber()) {
-    auto source_code_location = mojom::blink::SourceCodeLocation::New();
-    source_code_location->url = violation_data.sourceFile();
+    auto source_location = network::mojom::blink::SourceLocation::New();
+    source_location->url = violation_data.sourceFile();
     // The frontend expects 0-based line numbers.
-    source_code_location->line_number = violation_data.lineNumber() - 1;
-    source_code_location->column_number = violation_data.columnNumber();
-    cspDetails->source_code_location = std::move(source_code_location);
+    source_location->line = violation_data.lineNumber() - 1;
+    source_location->column = violation_data.columnNumber();
+    cspDetails->source_location = std::move(source_location);
   }
 
   auto details = mojom::blink::InspectorIssueDetails::New();
diff --git a/third_party/blink/renderer/core/html/link_web_bundle.h b/third_party/blink/renderer/core/html/link_web_bundle.h
index e0f78ba..1040a52 100644
--- a/third_party/blink/renderer/core/html/link_web_bundle.h
+++ b/third_party/blink/renderer/core/html/link_web_bundle.h
@@ -24,6 +24,10 @@
  public:
   explicit LinkWebBundle(HTMLLinkElement* owner);
   ~LinkWebBundle() override;
+
+  LinkWebBundle(const LinkWebBundle&) = delete;
+  LinkWebBundle& operator=(const LinkWebBundle&) = delete;
+
   void Trace(Visitor* visitor) const override;
 
   void NotifyLoaded();
@@ -46,6 +50,7 @@
   // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-parsing-the-index-section
   static KURL ParseResourceUrl(const AtomicString& str);
 
+ private:
   Member<WebBundleLoader> bundle_loader_;
 };
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
index 9d95fc85..81a444f 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
@@ -504,13 +504,12 @@
     }
     if (d->frame_ancestor)
       cspDetails.setFrameAncestor(BuildAffectedFrame(d->frame_ancestor));
-    if (d->source_code_location) {
-      auto source_location =
-          protocol::Audits::SourceCodeLocation::create()
-              .setUrl(d->source_code_location->url)
-              .setColumnNumber(d->source_code_location->column_number)
-              .setLineNumber(d->source_code_location->line_number)
-              .build();
+    if (d->source_location) {
+      auto source_location = protocol::Audits::SourceCodeLocation::create()
+                                 .setUrl(d->source_location->url)
+                                 .setColumnNumber(d->source_location->column)
+                                 .setLineNumber(d->source_location->line)
+                                 .build();
       cspDetails.setSourceCodeLocation(std::move(source_location));
     }
     issueDetails.setContentSecurityPolicyIssueDetails(cspDetails.build());
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index efce103..f82edd56 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1436,6 +1436,7 @@
       overflow_rect.Unite(outline_rect);
     }
   }
+  // TODO(schenney): Add in Text Decoration overflow rect
   return overflow_rect;
 }
 
diff --git a/third_party/blink/renderer/core/layout/text_decoration_offset_base.cc b/third_party/blink/renderer/core/layout/text_decoration_offset_base.cc
index d2918ff..40aaf9d 100644
--- a/third_party/blink/renderer/core/layout/text_decoration_offset_base.cc
+++ b/third_party/blink/renderer/core/layout/text_decoration_offset_base.cc
@@ -8,7 +8,7 @@
 
 #include <base/optional.h>
 
-#include "third_party/blink/renderer/core/paint/decoration_info.h"
+#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/platform/fonts/font_metrics.h"
 #include "third_party/blink/renderer/platform/fonts/font_vertical_position_type.h"
 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index eb4227d..fca6bf0 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -680,7 +680,7 @@
     return;
   }
 
-  ResourceError resource_error = error.value();
+  ResourceError resource_error(*error);
   if (network_utils::IsCertificateTransparencyRequiredError(
           resource_error.ErrorCode())) {
     GetUseCounterHelper().Count(
diff --git a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
index 0fb3ce4d..0c6ce1e 100644
--- a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
+++ b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
@@ -290,7 +290,7 @@
 }
 
 void WebAssociatedURLLoaderImpl::ClientAdapter::DidFailRedirectCheck() {
-  DidFail(WebURLError(ResourceError::Failure(NullURL())));
+  DidFail(ResourceError::Failure(NullURL()));
 }
 
 void WebAssociatedURLLoaderImpl::ClientAdapter::EnableErrorNotifications() {
@@ -448,9 +448,8 @@
   }
 
   if (!loader_) {
-    client_adapter_->DidFail(
-        WebURLError(ResourceError::CancelledDueToAccessCheckError(
-            request.Url(), ResourceRequestBlockedReason::kOther)));
+    client_adapter_->DidFail(ResourceError::CancelledDueToAccessCheckError(
+        request.Url(), ResourceRequestBlockedReason::kOther));
   }
   client_adapter_->EnableErrorNotifications();
 }
diff --git a/third_party/blink/renderer/core/paint/BUILD.gn b/third_party/blink/renderer/core/paint/BUILD.gn
index c347dce..17739fbc 100644
--- a/third_party/blink/renderer/core/paint/BUILD.gn
+++ b/third_party/blink/renderer/core/paint/BUILD.gn
@@ -66,7 +66,6 @@
     "css_mask_painter.h",
     "custom_scrollbar_theme.cc",
     "custom_scrollbar_theme.h",
-    "decoration_info.h",
     "details_marker_painter.cc",
     "details_marker_painter.h",
     "document_marker_painter.cc",
@@ -246,6 +245,8 @@
     "table_section_painter.h",
     "text_control_single_line_painter.cc",
     "text_control_single_line_painter.h",
+    "text_decoration_info.cc",
+    "text_decoration_info.h",
     "text_element_timing.cc",
     "text_element_timing.h",
     "text_paint_style.h",
diff --git a/third_party/blink/renderer/core/paint/applied_decoration_painter.cc b/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
index a408b2f..ec4fb71d 100644
--- a/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
+++ b/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
@@ -8,239 +8,34 @@
 
 namespace blink {
 
-namespace {
-
-static StrokeStyle TextDecorationStyleToStrokeStyle(
-    ETextDecorationStyle decoration_style) {
-  StrokeStyle stroke_style = kSolidStroke;
-  switch (decoration_style) {
-    case ETextDecorationStyle::kSolid:
-      stroke_style = kSolidStroke;
-      break;
-    case ETextDecorationStyle::kDouble:
-      stroke_style = kDoubleStroke;
-      break;
-    case ETextDecorationStyle::kDotted:
-      stroke_style = kDottedStroke;
-      break;
-    case ETextDecorationStyle::kDashed:
-      stroke_style = kDashedStroke;
-      break;
-    case ETextDecorationStyle::kWavy:
-      stroke_style = kWavyStroke;
-      break;
-  }
-
-  return stroke_style;
-}
-
-static void AdjustStepToDecorationLength(float& step,
-                                         float& control_point_distance,
-                                         float length) {
-  DCHECK_GT(step, 0);
-
-  if (length <= 0)
-    return;
-
-  unsigned step_count = static_cast<unsigned>(length / step);
-
-  // Each Bezier curve starts at the same pixel that the previous one
-  // ended. We need to subtract (stepCount - 1) pixels when calculating the
-  // length covered to account for that.
-  float uncovered_length = length - (step_count * step - (step_count - 1));
-  float adjustment = uncovered_length / step_count;
-  step += adjustment;
-  control_point_distance += adjustment;
-}
-
-}  // anonymous namespace
-
-Path AppliedDecorationPainter::PrepareDottedDashedStrokePath() {
-  // These coordinate transforms need to match what's happening in
-  // GraphicsContext's drawLineForText and drawLine.
-  int y = floorf(start_point_.Y() +
-                 std::max<float>(resolved_thickness_ / 2.0f, 0.5f));
-  Path stroke_path;
-  FloatPoint rounded_start_point(start_point_.X(), y);
-  FloatPoint rounded_end_point(rounded_start_point +
-                               FloatPoint(decoration_info_.width, 0));
-  context_.AdjustLineToPixelBoundaries(rounded_start_point, rounded_end_point,
-                                       roundf(resolved_thickness_));
-  stroke_path.MoveTo(rounded_start_point);
-  stroke_path.AddLineTo(rounded_end_point);
-  return stroke_path;
-}
-
-FloatRect AppliedDecorationPainter::Bounds() {
-  StrokeData stroke_data;
-  stroke_data.SetThickness(resolved_thickness_);
-
-  switch (decoration_.Style()) {
-    case ETextDecorationStyle::kDotted:
-    case ETextDecorationStyle::kDashed: {
-      stroke_data.SetStyle(
-          TextDecorationStyleToStrokeStyle(decoration_.Style()));
-      return PrepareDottedDashedStrokePath().StrokeBoundingRect(stroke_data);
-    }
-    case ETextDecorationStyle::kWavy:
-      return PrepareWavyStrokePath().StrokeBoundingRect(stroke_data);
-    case ETextDecorationStyle::kDouble:
-      if (double_offset_ > 0) {
-        return FloatRect(start_point_.X(), start_point_.Y(),
-                         decoration_info_.width,
-                         double_offset_ + resolved_thickness_);
-      }
-      return FloatRect(start_point_.X(), start_point_.Y() + double_offset_,
-                       decoration_info_.width,
-                       -double_offset_ + resolved_thickness_);
-    case ETextDecorationStyle::kSolid:
-      return FloatRect(start_point_.X(), start_point_.Y(),
-                       decoration_info_.width, resolved_thickness_);
-    default:
-      break;
-  }
-  NOTREACHED();
-  return FloatRect();
-}
-
 void AppliedDecorationPainter::Paint() {
-  context_.SetStrokeStyle(
-      TextDecorationStyleToStrokeStyle(decoration_.Style()));
-  context_.SetStrokeColor(decoration_.GetColor());
+  context_.SetStrokeStyle(decoration_info_.StrokeStyle());
+  context_.SetStrokeColor(decoration_info_.Color());
 
-  switch (decoration_.Style()) {
+  switch (decoration_info_.DecorationStyle()) {
     case ETextDecorationStyle::kWavy:
       StrokeWavyTextDecoration();
       break;
     case ETextDecorationStyle::kDotted:
     case ETextDecorationStyle::kDashed:
-      context_.SetShouldAntialias(decoration_info_.antialias);
+      context_.SetShouldAntialias(decoration_info_.ShouldAntialias());
       FALLTHROUGH;
     default:
-      context_.DrawLineForText(start_point_, decoration_info_.width);
+      context_.DrawLineForText(decoration_info_.StartPoint(line_),
+                               decoration_info_.Width());
 
-      if (decoration_.Style() == ETextDecorationStyle::kDouble) {
-        context_.DrawLineForText(start_point_ + FloatPoint(0, double_offset_),
-                                 decoration_info_.width);
+      if (decoration_info_.DecorationStyle() == ETextDecorationStyle::kDouble) {
+        context_.DrawLineForText(
+            decoration_info_.StartPoint(line_) +
+                FloatPoint(0, decoration_info_.DoubleOffset(line_)),
+            decoration_info_.Width());
       }
   }
 }
 
 void AppliedDecorationPainter::StrokeWavyTextDecoration() {
   context_.SetShouldAntialias(true);
-  context_.StrokePath(PrepareWavyStrokePath());
-}
-
-/*
- * Prepare a path for a cubic Bezier curve and repeat the same pattern long the
- * the decoration's axis.  The start point (p1), controlPoint1, controlPoint2
- * and end point (p2) of the Bezier curve form a diamond shape:
- *
- *                              step
- *                         |-----------|
- *
- *                   controlPoint1
- *                         +
- *
- *
- *                  . .
- *                .     .
- *              .         .
- * (x1, y1) p1 +           .            + p2 (x2, y2) - <--- Decoration's axis
- *                          .         .               |
- *                            .     .                 |
- *                              . .                   | controlPointDistance
- *                                                    |
- *                                                    |
- *                         +                          -
- *                   controlPoint2
- *
- *             |-----------|
- *                 step
- */
-Path AppliedDecorationPainter::PrepareWavyStrokePath() {
-  FloatPoint p1(start_point_ +
-                FloatPoint(0, double_offset_ * wavy_offset_factor_));
-  FloatPoint p2(
-      start_point_ +
-      FloatPoint(decoration_info_.width, double_offset_ * wavy_offset_factor_));
-
-  context_.AdjustLineToPixelBoundaries(p1, p2, resolved_thickness_);
-
-  Path path;
-  path.MoveTo(p1);
-
-  // Distance between decoration's axis and Bezier curve's control points.
-  // The height of the curve is based on this distance. Use a minimum of 6
-  // pixels distance since
-  // the actual curve passes approximately at half of that distance, that is 3
-  // pixels.
-  // The minimum height of the curve is also approximately 3 pixels. Increases
-  // the curve's height
-  // as strockThickness increases to make the curve looks better.
-  float control_point_distance = 3 * std::max<float>(2, resolved_thickness_);
-
-  // Increment used to form the diamond shape between start point (p1), control
-  // points and end point (p2) along the axis of the decoration. Makes the
-  // curve wider as strockThickness increases to make the curve looks better.
-  float step = 2 * std::max<float>(2, resolved_thickness_);
-
-  bool is_vertical_line = (p1.X() == p2.X());
-
-  if (is_vertical_line) {
-    DCHECK(p1.X() == p2.X());
-
-    float x_axis = p1.X();
-    float y1;
-    float y2;
-
-    if (p1.Y() < p2.Y()) {
-      y1 = p1.Y();
-      y2 = p2.Y();
-    } else {
-      y1 = p2.Y();
-      y2 = p1.Y();
-    }
-
-    AdjustStepToDecorationLength(step, control_point_distance, y2 - y1);
-    FloatPoint control_point1(x_axis + control_point_distance, 0);
-    FloatPoint control_point2(x_axis - control_point_distance, 0);
-
-    for (float y = y1; y + 2 * step <= y2;) {
-      control_point1.SetY(y + step);
-      control_point2.SetY(y + step);
-      y += 2 * step;
-      path.AddBezierCurveTo(control_point1, control_point2,
-                            FloatPoint(x_axis, y));
-    }
-  } else {
-    DCHECK(p1.Y() == p2.Y());
-
-    float y_axis = p1.Y();
-    float x1;
-    float x2;
-
-    if (p1.X() < p2.X()) {
-      x1 = p1.X();
-      x2 = p2.X();
-    } else {
-      x1 = p2.X();
-      x2 = p1.X();
-    }
-
-    AdjustStepToDecorationLength(step, control_point_distance, x2 - x1);
-    FloatPoint control_point1(0, y_axis + control_point_distance);
-    FloatPoint control_point2(0, y_axis - control_point_distance);
-
-    for (float x = x1; x + 2 * step <= x2;) {
-      control_point1.SetX(x + step);
-      control_point2.SetX(x + step);
-      x += 2 * step;
-      path.AddBezierCurveTo(control_point1, control_point2,
-                            FloatPoint(x, y_axis));
-    }
-  }
-  return path;
+  context_.StrokePath(decoration_info_.PrepareWavyStrokePath(line_));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/applied_decoration_painter.h b/third_party/blink/renderer/core/paint/applied_decoration_painter.h
index cd37112..004cc50 100644
--- a/third_party/blink/renderer/core/paint/applied_decoration_painter.h
+++ b/third_party/blink/renderer/core/paint/applied_decoration_painter.h
@@ -5,13 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_APPLIED_DECORATION_PAINTER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_APPLIED_DECORATION_PAINTER_H_
 
-#include "third_party/blink/renderer/core/paint/decoration_info.h"
-#include "third_party/blink/renderer/core/style/applied_text_decoration.h"
-#include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/platform/geometry/float_point.h"
-#include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-#include "third_party/blink/renderer/platform/graphics/path.h"
+#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
@@ -25,38 +19,18 @@
 
  public:
   AppliedDecorationPainter(GraphicsContext& context,
-                           const DecorationInfo& decoration_info,
-                           float start_point_y_offset,
-                           const AppliedTextDecoration& decoration,
-                           size_t decoration_info_thickness_index,
-                           float double_offset,
-                           int wavy_offset_factor)
-      : context_(context),
-        start_point_(decoration_info.local_origin +
-                     FloatPoint(0, start_point_y_offset)),
-        decoration_info_(decoration_info),
-        resolved_thickness_(decoration_info.applied_decorations_thickness
-                                [decoration_info_thickness_index]),
-        decoration_(decoration),
-        double_offset_(double_offset),
-        wavy_offset_factor_(wavy_offset_factor) {}
+                           const TextDecorationInfo& decoration_info,
+                           TextDecoration line)
+      : context_(context), decoration_info_(decoration_info), line_(line) {}
 
   void Paint();
-  FloatRect Bounds();
 
  private:
   void StrokeWavyTextDecoration();
 
-  Path PrepareWavyStrokePath();
-  Path PrepareDottedDashedStrokePath();
-
   GraphicsContext& context_;
-  const FloatPoint start_point_;
-  const DecorationInfo& decoration_info_;
-  float resolved_thickness_;
-  const AppliedTextDecoration& decoration_;
-  const float double_offset_;
-  const int wavy_offset_factor_;
+  const TextDecorationInfo& decoration_info_;
+  TextDecoration line_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/decoration_info.h b/third_party/blink/renderer/core/paint/decoration_info.h
deleted file mode 100644
index affebdf..0000000
--- a/third_party/blink/renderer/core/paint/decoration_info.h
+++ /dev/null
@@ -1,46 +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 THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_DECORATION_INFO_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_DECORATION_INFO_H_
-
-#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/geometry/float_point.h"
-#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class ComputedStyle;
-class SimpleFontData;
-
-enum class ResolvedUnderlinePosition {
-  kNearAlphabeticBaselineAuto,
-  kNearAlphabeticBaselineFromFont,
-  kUnder,
-  kOver
-};
-
-// Holds text decoration painting values to be computed once and subsequently
-// use multiple times to handle decoration paint order correctly. See also
-// https://www.w3.org/TR/css-text-decor-3/#painting-order
-struct DecorationInfo final {
-  STACK_ALLOCATED();
-
- public:
-  LayoutUnit width;
-  FloatPoint local_origin;
-  bool antialias;
-  float baseline;
-  const ComputedStyle* style;
-  const SimpleFontData* font_data;
-  FontBaseline baseline_type;
-  ResolvedUnderlinePosition underline_position;
-  Vector<float> applied_decorations_thickness;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_DECORATION_INFO_H_
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index 60c8762..e68f583 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -18,11 +18,11 @@
 #include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
 #include "third_party/blink/renderer/core/layout/text_decoration_offset.h"
 #include "third_party/blink/renderer/core/paint/applied_decoration_painter.h"
-#include "third_party/blink/renderer/core/paint/decoration_info.h"
 #include "third_party/blink/renderer/core/paint/document_marker_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
 #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
+#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/core/paint/text_painter.h"
 #include "third_party/blink/renderer/platform/graphics/dom_node_id.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
@@ -362,7 +362,7 @@
 
   if (!paint_selected_text_only) {
     // Paint text decorations except line-through.
-    DecorationInfo decoration_info;
+    base::Optional<TextDecorationInfo> decoration_info;
     bool has_line_through_decoration = false;
     if (style_to_use.TextDecorationsInEffect() != TextDecoration::kNone &&
         inline_text_box_.Truncation() != kCFullTruncation) {
@@ -373,14 +373,13 @@
           EnclosingUnderlineObject(&inline_text_box_);
       const ComputedStyle* decorating_box_style =
           decorating_box ? decorating_box.Style() : nullptr;
-      text_painter.ComputeDecorationInfo(decoration_info, box_origin,
-                                         local_origin, width,
-                                         inline_text_box_.Root().BaselineType(),
-                                         style_to_use, decorating_box_style);
-      TextDecorationOffset decoration_offset(*decoration_info.style,
+      decoration_info.emplace(box_origin, local_origin, width,
+                              inline_text_box_.Root().BaselineType(),
+                              style_to_use, decorating_box_style);
+      TextDecorationOffset decoration_offset(decoration_info->Style(),
                                              &inline_text_box_, decorating_box);
       text_painter.PaintDecorationsExceptLineThrough(
-          decoration_offset, decoration_info, paint_info,
+          decoration_offset, decoration_info.value(), paint_info,
           style_to_use.AppliedTextDecorations(), text_style,
           &has_line_through_decoration);
     }
@@ -404,8 +403,8 @@
     // Paint line-through decoration if needed.
     if (has_line_through_decoration) {
       text_painter.PaintDecorationsOnlyLineThrough(
-          decoration_info, paint_info, style_to_use.AppliedTextDecorations(),
-          text_style);
+          decoration_info.value(), paint_info,
+          style_to_use.AppliedTextDecorations(), text_style);
     }
   }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 3f7ad34..966dd99 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -660,7 +660,7 @@
   const unsigned length = fragment_paint_info.to - fragment_paint_info.from;
   if (!selection || !selection->ShouldPaintSelectedTextOnly()) {
     // Paint text decorations except line-through.
-    DecorationInfo decoration_info;
+    base::Optional<TextDecorationInfo> decoration_info;
     bool has_line_through_decoration = false;
     if (style.TextDecorationsInEffect() != TextDecoration::kNone &&
         // Ellipsis should not have text decorations. This is not defined, but 4
@@ -672,14 +672,14 @@
       const ComputedStyle* decorating_box_style =
           decorating_box ? &decorating_box->Style() : nullptr;
 
-      text_painter.ComputeDecorationInfo(
-          decoration_info, box_rect.offset, local_origin, width,
-          style.GetFontBaseline(), style, decorating_box_style);
+      decoration_info.emplace(box_rect.offset, local_origin, width,
+                              style.GetFontBaseline(), style,
+                              decorating_box_style);
 
       NGTextDecorationOffset decoration_offset(
-          *decoration_info.style, text_item.Style(), decorating_box);
+          decoration_info->Style(), text_item.Style(), decorating_box);
       text_painter.PaintDecorationsExceptLineThrough(
-          decoration_offset, decoration_info, paint_info,
+          decoration_offset, decoration_info.value(), paint_info,
           style.AppliedTextDecorations(), text_style,
           &has_line_through_decoration);
     }
@@ -697,7 +697,7 @@
     // Paint line-through decoration if needed.
     if (has_line_through_decoration) {
       text_painter.PaintDecorationsOnlyLineThrough(
-          decoration_info, paint_info, style.AppliedTextDecorations(),
+          decoration_info.value(), paint_info, style.AppliedTextDecorations(),
           text_style);
     }
   }
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.cc b/third_party/blink/renderer/core/paint/text_decoration_info.cc
new file mode 100644
index 0000000..c0f6afca
--- /dev/null
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.cc
@@ -0,0 +1,415 @@
+// 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 "third_party/blink/renderer/core/paint/text_decoration_info.h"
+
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/geometry/length_functions.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
+
+namespace blink {
+
+namespace {
+
+static int kUndefinedDecorationIndex = -1;
+
+static ResolvedUnderlinePosition ResolveUnderlinePosition(
+    const ComputedStyle& style,
+    FontBaseline baseline_type) {
+  // |auto| should resolve to |under| to avoid drawing through glyphs in
+  // scripts where it would not be appropriate (e.g., ideographs.)
+  // However, this has performance implications. For now, we only work with
+  // vertical text.
+  switch (baseline_type) {
+    case kAlphabeticBaseline:
+      if (style.TextUnderlinePosition() & kTextUnderlinePositionUnder)
+        return ResolvedUnderlinePosition::kUnder;
+      if (style.TextUnderlinePosition() & kTextUnderlinePositionFromFont)
+        return ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont;
+      return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
+    case kIdeographicBaseline:
+      // Compute language-appropriate default underline position.
+      // https://drafts.csswg.org/css-text-decor-3/#default-stylesheet
+      UScriptCode script = style.GetFontDescription().GetScript();
+      if (script == USCRIPT_KATAKANA_OR_HIRAGANA || script == USCRIPT_HANGUL) {
+        if (style.TextUnderlinePosition() & kTextUnderlinePositionLeft) {
+          return ResolvedUnderlinePosition::kUnder;
+        }
+        return ResolvedUnderlinePosition::kOver;
+      }
+      if (style.TextUnderlinePosition() & kTextUnderlinePositionRight) {
+        return ResolvedUnderlinePosition::kOver;
+      }
+      return ResolvedUnderlinePosition::kUnder;
+  }
+  NOTREACHED();
+  return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
+}
+
+static bool ShouldSetDecorationAntialias(const ComputedStyle& style) {
+  for (const auto& decoration : style.AppliedTextDecorations()) {
+    ETextDecorationStyle decoration_style = decoration.Style();
+    if (decoration_style == ETextDecorationStyle::kDotted ||
+        decoration_style == ETextDecorationStyle::kDashed)
+      return true;
+  }
+  return false;
+}
+
+static float ComputeDecorationThickness(
+    const TextDecorationThickness text_decoration_thickness,
+    const ComputedStyle& style,
+    const SimpleFontData* font_data) {
+  float auto_underline_thickness =
+      std::max(1.f, style.ComputedFontSize() / 10.f);
+
+  if (text_decoration_thickness.IsAuto())
+    return auto_underline_thickness;
+
+  // In principle we would not need to test for font_data if
+  // |text_decoration_thickness.Thickness()| is fixed, but a null font_data here
+  // would be a rare / error situation anyway, so practically, we can
+  // early out here.
+  if (!font_data)
+    return auto_underline_thickness;
+
+  if (text_decoration_thickness.IsFromFont()) {
+    base::Optional<float> underline_thickness_font_metric =
+        font_data->GetFontMetrics().UnderlineThickness().value();
+
+    if (!underline_thickness_font_metric)
+      return auto_underline_thickness;
+
+    return std::max(1.f, underline_thickness_font_metric.value());
+  }
+
+  DCHECK(!text_decoration_thickness.IsFromFont());
+
+  const Length& thickness_length = text_decoration_thickness.Thickness();
+  float font_size = font_data->PlatformData().size();
+  float text_decoration_thickness_pixels =
+      FloatValueForLength(thickness_length, font_size);
+
+  return std::max(1.f, text_decoration_thickness_pixels);
+}
+
+static void AdjustStepToDecorationLength(float& step,
+                                         float& control_point_distance,
+                                         float length) {
+  DCHECK_GT(step, 0);
+
+  if (length <= 0)
+    return;
+
+  unsigned step_count = static_cast<unsigned>(length / step);
+
+  // Each Bezier curve starts at the same pixel that the previous one
+  // ended. We need to subtract (stepCount - 1) pixels when calculating the
+  // length covered to account for that.
+  float uncovered_length = length - (step_count * step - (step_count - 1));
+  float adjustment = uncovered_length / step_count;
+  step += adjustment;
+  control_point_distance += adjustment;
+}
+
+static enum StrokeStyle TextDecorationStyleToStrokeStyle(
+    ETextDecorationStyle decoration_style) {
+  enum StrokeStyle stroke_style = kSolidStroke;
+  switch (decoration_style) {
+    case ETextDecorationStyle::kSolid:
+      stroke_style = kSolidStroke;
+      break;
+    case ETextDecorationStyle::kDouble:
+      stroke_style = kDoubleStroke;
+      break;
+    case ETextDecorationStyle::kDotted:
+      stroke_style = kDottedStroke;
+      break;
+    case ETextDecorationStyle::kDashed:
+      stroke_style = kDashedStroke;
+      break;
+    case ETextDecorationStyle::kWavy:
+      stroke_style = kWavyStroke;
+      break;
+  }
+
+  return stroke_style;
+}
+
+static int TextDecorationToLineDataIndex(TextDecoration line) {
+  switch (line) {
+    case TextDecoration::kUnderline:
+      return 0;
+    case TextDecoration::kOverline:
+      return 1;
+    case TextDecoration::kLineThrough:
+      return 2;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+}  // anonymous namespace
+
+TextDecorationInfo::TextDecorationInfo(
+    const PhysicalOffset& box_origin,
+    PhysicalOffset local_origin,
+    LayoutUnit width,
+    FontBaseline baseline_type,
+    const ComputedStyle& style,
+    const ComputedStyle* decorating_box_style)
+    : style_(style),
+      baseline_type_(baseline_type),
+      width_(width),
+      font_data_(style_.GetFont().PrimaryFont()),
+      baseline_(font_data_ ? font_data_->GetFontMetrics().FloatAscent() : 0),
+      underline_position_(ResolveUnderlinePosition(style_, baseline_type_)),
+      local_origin_(FloatPoint(local_origin)),
+      antialias_(ShouldSetDecorationAntialias(style)),
+      decoration_index_(kUndefinedDecorationIndex) {
+  DCHECK(font_data_);
+
+  for (const AppliedTextDecoration& decoration :
+       style_.AppliedTextDecorations()) {
+    applied_decorations_thickness_.push_back(ComputeUnderlineThickness(
+        decoration.Thickness(), decorating_box_style));
+  }
+  DCHECK_EQ(style_.AppliedTextDecorations().size(),
+            applied_decorations_thickness_.size());
+}
+
+void TextDecorationInfo::SetDecorationIndex(int decoration_index) {
+  DCHECK_LT(decoration_index,
+            static_cast<int>(applied_decorations_thickness_.size()));
+  decoration_index_ = decoration_index;
+}
+
+void TextDecorationInfo::SetPerLineData(TextDecoration line,
+                                        float line_offset,
+                                        float double_offset,
+                                        int wavy_offset_factor) {
+  int index = TextDecorationToLineDataIndex(line);
+  line_data_[index].line_offset = line_offset;
+  line_data_[index].double_offset = double_offset;
+  line_data_[index].wavy_offset_factor = wavy_offset_factor;
+}
+
+ETextDecorationStyle TextDecorationInfo::DecorationStyle() const {
+  return style_.AppliedTextDecorations()[decoration_index_].Style();
+}
+
+Color TextDecorationInfo::Color() const {
+  return style_.AppliedTextDecorations()[decoration_index_].GetColor();
+}
+
+FloatPoint TextDecorationInfo::StartPoint(TextDecoration line) const {
+  return local_origin_ +
+         FloatPoint(
+             0, line_data_[TextDecorationToLineDataIndex(line)].line_offset);
+}
+float TextDecorationInfo::DoubleOffset(TextDecoration line) const {
+  return line_data_[TextDecorationToLineDataIndex(line)].double_offset;
+}
+
+enum StrokeStyle TextDecorationInfo::StrokeStyle() const {
+  return TextDecorationStyleToStrokeStyle(DecorationStyle());
+}
+
+float TextDecorationInfo::ComputeUnderlineThickness(
+    const TextDecorationThickness& applied_decoration_thickness,
+    const ComputedStyle* decorating_box_style) {
+  float thickness = 0;
+  if ((underline_position_ ==
+       ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto) ||
+      underline_position_ ==
+          ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont) {
+    thickness = ComputeDecorationThickness(applied_decoration_thickness, style_,
+                                           style_.GetFont().PrimaryFont());
+  } else {
+    // Compute decorating box. Position and thickness are computed from the
+    // decorating box.
+    // Only for non-Roman for now for the performance implications.
+    // https:// drafts.csswg.org/css-text-decor-3/#decorating-box
+    if (decorating_box_style) {
+      thickness = ComputeDecorationThickness(
+          applied_decoration_thickness, *decorating_box_style,
+          decorating_box_style->GetFont().PrimaryFont());
+    } else {
+      thickness = ComputeDecorationThickness(
+          applied_decoration_thickness, style_, style_.GetFont().PrimaryFont());
+    }
+  }
+  return thickness;
+}
+
+FloatRect TextDecorationInfo::BoundsForLine(TextDecoration line) const {
+  FloatPoint start_point = StartPoint(line);
+  switch (DecorationStyle()) {
+    case ETextDecorationStyle::kDotted:
+    case ETextDecorationStyle::kDashed: {
+      return BoundsForDottedOrDashed(line);
+    }
+    case ETextDecorationStyle::kWavy:
+      return BoundsForWavy(line);
+    case ETextDecorationStyle::kDouble:
+      if (DoubleOffset(line) > 0) {
+        return FloatRect(start_point.X(), start_point.Y(), width_,
+                         DoubleOffset(line) + ResolvedThickness());
+      }
+      return FloatRect(start_point.X(), start_point.Y() + DoubleOffset(line),
+                       width_, -DoubleOffset(line) + ResolvedThickness());
+    case ETextDecorationStyle::kSolid:
+      return FloatRect(start_point.X(), start_point.Y(), width_,
+                       ResolvedThickness());
+    default:
+      break;
+  }
+  NOTREACHED();
+  return FloatRect();
+}
+
+FloatRect TextDecorationInfo::BoundsForDottedOrDashed(
+    TextDecoration line) const {
+  // These coordinate transforms need to match what's happening in
+  // GraphicsContext's drawLineForText and drawLine.
+  FloatPoint start_point = StartPoint(line);
+  int y = floorf(start_point.Y() +
+                 std::max<float>(ResolvedThickness() / 2.0f, 0.5f));
+  FloatPoint rounded_start_point(start_point.X(), y);
+  FloatPoint rounded_end_point(rounded_start_point + FloatPoint(width_, 0));
+  GraphicsContext::AdjustLineToPixelBoundaries(
+      rounded_start_point, rounded_end_point, roundf(ResolvedThickness()));
+
+  Path stroke_path;
+  stroke_path.MoveTo(rounded_start_point);
+  stroke_path.AddLineTo(rounded_end_point);
+
+  StrokeData stroke_data;
+  stroke_data.SetThickness(ResolvedThickness());
+  stroke_data.SetStyle(TextDecorationStyleToStrokeStyle(DecorationStyle()));
+  return stroke_path.StrokeBoundingRect(stroke_data);
+}
+
+FloatRect TextDecorationInfo::BoundsForWavy(TextDecoration line) const {
+  StrokeData stroke_data;
+  stroke_data.SetThickness(ResolvedThickness());
+  return PrepareWavyStrokePath(line).StrokeBoundingRect(stroke_data);
+}
+
+/*
+ * Prepare a path for a cubic Bezier curve and repeat the same pattern long the
+ * the decoration's axis.  The start point (p1), controlPoint1, controlPoint2
+ * and end point (p2) of the Bezier curve form a diamond shape:
+ *
+ *                              step
+ *                         |-----------|
+ *
+ *                   controlPoint1
+ *                         +
+ *
+ *
+ *                  . .
+ *                .     .
+ *              .         .
+ * (x1, y1) p1 +           .            + p2 (x2, y2) - <--- Decoration's axis
+ *                          .         .               |
+ *                            .     .                 |
+ *                              . .                   | controlPointDistance
+ *                                                    |
+ *                                                    |
+ *                         +                          -
+ *                   controlPoint2
+ *
+ *             |-----------|
+ *                 step
+ */
+Path TextDecorationInfo::PrepareWavyStrokePath(TextDecoration line) const {
+  FloatPoint start_point = StartPoint(line);
+  float wave_offset =
+      DoubleOffset(line) *
+      line_data_[TextDecorationToLineDataIndex(line)].wavy_offset_factor;
+
+  FloatPoint p1(start_point + FloatPoint(0, wave_offset));
+  FloatPoint p2(start_point + FloatPoint(width_, wave_offset));
+
+  GraphicsContext::AdjustLineToPixelBoundaries(p1, p2, ResolvedThickness());
+
+  Path path;
+  path.MoveTo(p1);
+
+  // Distance between decoration's axis and Bezier curve's control points.
+  // The height of the curve is based on this distance. Use a minimum of 6
+  // pixels distance since
+  // the actual curve passes approximately at half of that distance, that is 3
+  // pixels.
+  // The minimum height of the curve is also approximately 3 pixels. Increases
+  // the curve's height
+  // as strockThickness increases to make the curve looks better.
+  float control_point_distance = 3 * std::max<float>(2, ResolvedThickness());
+
+  // Increment used to form the diamond shape between start point (p1), control
+  // points and end point (p2) along the axis of the decoration. Makes the
+  // curve wider as strockThickness increases to make the curve looks better.
+  float step = 2 * std::max<float>(2, ResolvedThickness());
+
+  bool is_vertical_line = (p1.X() == p2.X());
+
+  if (is_vertical_line) {
+    DCHECK(p1.X() == p2.X());
+
+    float x_axis = p1.X();
+    float y1;
+    float y2;
+
+    if (p1.Y() < p2.Y()) {
+      y1 = p1.Y();
+      y2 = p2.Y();
+    } else {
+      y1 = p2.Y();
+      y2 = p1.Y();
+    }
+
+    AdjustStepToDecorationLength(step, control_point_distance, y2 - y1);
+    FloatPoint control_point1(x_axis + control_point_distance, 0);
+    FloatPoint control_point2(x_axis - control_point_distance, 0);
+
+    for (float y = y1; y + 2 * step <= y2;) {
+      control_point1.SetY(y + step);
+      control_point2.SetY(y + step);
+      y += 2 * step;
+      path.AddBezierCurveTo(control_point1, control_point2,
+                            FloatPoint(x_axis, y));
+    }
+  } else {
+    DCHECK(p1.Y() == p2.Y());
+
+    float y_axis = p1.Y();
+    float x1;
+    float x2;
+
+    if (p1.X() < p2.X()) {
+      x1 = p1.X();
+      x2 = p2.X();
+    } else {
+      x1 = p2.X();
+      x2 = p1.X();
+    }
+
+    AdjustStepToDecorationLength(step, control_point_distance, x2 - x1);
+    FloatPoint control_point1(0, y_axis + control_point_distance);
+    FloatPoint control_point2(0, y_axis - control_point_distance);
+
+    for (float x = x1; x + 2 * step <= x2;) {
+      control_point1.SetX(x + step);
+      control_point2.SetX(x + step);
+      x += 2 * step;
+      path.AddBezierCurveTo(control_point1, control_point2,
+                            FloatPoint(x, y_axis));
+    }
+  }
+  return path;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.h b/third_party/blink/renderer/core/paint/text_decoration_info.h
new file mode 100644
index 0000000..0be5eb54
--- /dev/null
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.h
@@ -0,0 +1,133 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TEXT_DECORATION_INFO_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TEXT_DECORATION_INFO_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
+#include "third_party/blink/renderer/core/style/applied_text_decoration.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
+#include "third_party/blink/renderer/platform/geometry/float_point.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/graphics/path.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class ComputedStyle;
+class SimpleFontData;
+
+enum class ResolvedUnderlinePosition {
+  kNearAlphabeticBaselineAuto,
+  kNearAlphabeticBaselineFromFont,
+  kUnder,
+  kOver
+};
+
+// Container for computing and storing information for text decoration
+// invalidation and painting. See also
+// https://www.w3.org/TR/css-text-decor-3/#painting-order
+class CORE_EXPORT TextDecorationInfo {
+ public:
+  TextDecorationInfo(const PhysicalOffset& box_origin,
+                     PhysicalOffset local_origin,
+                     LayoutUnit width,
+                     FontBaseline baseline_type,
+                     const ComputedStyle& style,
+                     const ComputedStyle* decorating_box_style);
+
+  // Set the decoration to use when painting and returning values.
+  // Must be set before calling any other method, and can be called
+  // again at any time. This object will use the most recently given
+  // index for any computation that uses data from an
+  // AppliedTextDecoration object. The index must be a valid index
+  // the AppliedTextDecorations contained within the style passed
+  // at construction.
+  void SetDecorationIndex(int decoration_index);
+
+  // Set data for one of the text decoration lines: over, under or
+  // through. Must be called before trying to paint or compute bounds
+  // for a line.
+  void SetPerLineData(TextDecoration line,
+                      float line_offset,
+                      float double_offset,
+                      int wavy_offset_factor);
+
+  // These methods do not depend on SetDecorationIndex
+  LayoutUnit Width() const { return width_; }
+  float Baseline() const { return baseline_; }
+  const ComputedStyle& Style() const { return style_; }
+  const SimpleFontData* FontData() const { return font_data_; }
+  ResolvedUnderlinePosition UnderlinePosition() const {
+    return underline_position_;
+  }
+  bool ShouldAntialias() const { return antialias_; }
+  float InkSkipClipUpper(float bounds_upper) const {
+    return -baseline_ + bounds_upper - local_origin_.Y();
+  }
+
+  // SetDecorationIndex must be called before using these methods.
+  ETextDecorationStyle DecorationStyle() const;
+  Color Color() const;
+  float ResolvedThickness() const {
+    return applied_decorations_thickness_[decoration_index_];
+  }
+  enum StrokeStyle StrokeStyle() const;
+
+  // SetPerLineData must be called with the line argument before using
+  // the remaining methods.
+  FloatPoint StartPoint(TextDecoration line) const;
+  float DoubleOffset(TextDecoration line) const;
+
+  // Computed bounds for all the decorations in the style passed at
+  // construction.
+  FloatRect Bounds() const;
+
+  // Compute bounds for the given line and the current decoration.
+  FloatRect BoundsForLine(TextDecoration line) const;
+
+  // Return a path for a wavy line at the given position, for the
+  // current decoration.
+  Path PrepareWavyStrokePath(TextDecoration line) const;
+
+ private:
+  float ComputeUnderlineThickness(
+      const TextDecorationThickness& applied_decoration_thickness,
+      const ComputedStyle* decorating_box_style);
+
+  FloatRect BoundsForDottedOrDashed(TextDecoration line) const;
+  FloatRect BoundsForWavy(TextDecoration line) const;
+
+  const ComputedStyle& style_;
+  const FontBaseline baseline_type_;
+  const LayoutUnit width_;
+  const SimpleFontData* font_data_;
+  const float baseline_;
+  ResolvedUnderlinePosition underline_position_;
+  FloatPoint local_origin_;
+  bool antialias_;
+  Vector<float> applied_decorations_thickness_;
+
+  int decoration_index_;
+
+  /* We need to store data for up to 3 lines: Underline, Overline and
+     LineThrough. Unfortunately the enum for these are bitfield indices, not
+     directly useful as indexes. So explicitly convert in place
+     when necessary.
+  */
+  struct PerLineData {
+    float line_offset;
+    float double_offset;
+    int wavy_offset_factor;
+  };
+  PerLineData line_data_[3];
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TEXT_DECORATION_INFO_H_
diff --git a/third_party/blink/renderer/core/paint/text_painter_base.cc b/third_party/blink/renderer/core/paint/text_painter_base.cc
index 2e87f9c..f70f534 100644
--- a/third_party/blink/renderer/core/paint/text_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/text_painter_base.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/paint/box_painter_base.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
+#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style/shadow_list.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
@@ -30,86 +31,6 @@
 // implementation.
 constexpr float kDecorationClipMaxDilation = 13;
 
-static ResolvedUnderlinePosition ResolveUnderlinePosition(
-    const ComputedStyle& style,
-    FontBaseline baseline_type) {
-  // |auto| should resolve to |under| to avoid drawing through glyphs in
-  // scripts where it would not be appropriate (e.g., ideographs.)
-  // However, this has performance implications. For now, we only work with
-  // vertical text.
-  switch (baseline_type) {
-    case kAlphabeticBaseline:
-      if (style.TextUnderlinePosition() & kTextUnderlinePositionUnder)
-        return ResolvedUnderlinePosition::kUnder;
-      if (style.TextUnderlinePosition() & kTextUnderlinePositionFromFont)
-        return ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont;
-      return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
-    case kIdeographicBaseline:
-      // Compute language-appropriate default underline position.
-      // https://drafts.csswg.org/css-text-decor-3/#default-stylesheet
-      UScriptCode script = style.GetFontDescription().GetScript();
-      if (script == USCRIPT_KATAKANA_OR_HIRAGANA || script == USCRIPT_HANGUL) {
-        if (style.TextUnderlinePosition() & kTextUnderlinePositionLeft) {
-          return ResolvedUnderlinePosition::kUnder;
-        }
-        return ResolvedUnderlinePosition::kOver;
-      }
-      if (style.TextUnderlinePosition() & kTextUnderlinePositionRight) {
-        return ResolvedUnderlinePosition::kOver;
-      }
-      return ResolvedUnderlinePosition::kUnder;
-  }
-  NOTREACHED();
-  return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
-}
-
-static bool ShouldSetDecorationAntialias(const ComputedStyle& style) {
-  for (const auto& decoration : style.AppliedTextDecorations()) {
-    ETextDecorationStyle decoration_style = decoration.Style();
-    if (decoration_style == ETextDecorationStyle::kDotted ||
-        decoration_style == ETextDecorationStyle::kDashed)
-      return true;
-  }
-  return false;
-}
-
-float ComputeDecorationThickness(
-    const TextDecorationThickness text_decoration_thickness,
-    const ComputedStyle& style,
-    const SimpleFontData* font_data) {
-  float auto_underline_thickness =
-      std::max(1.f, style.ComputedFontSize() / 10.f);
-
-  if (text_decoration_thickness.IsAuto())
-    return auto_underline_thickness;
-
-  // In principle we would not need to test for font_data if
-  // |text_decoration_thickness.Thickness()| is fixed, but a null font_data here
-  // would be a rare / error situation anyway, so practically, we can
-  // early out here.
-  if (!font_data)
-    return auto_underline_thickness;
-
-  if (text_decoration_thickness.IsFromFont()) {
-    base::Optional<float> underline_thickness_font_metric =
-        font_data->GetFontMetrics().UnderlineThickness().value();
-
-    if (!underline_thickness_font_metric)
-      return auto_underline_thickness;
-
-    return std::max(1.f, underline_thickness_font_metric.value());
-  }
-
-  DCHECK(!text_decoration_thickness.IsFromFont());
-
-  const Length& thickness_length = text_decoration_thickness.Thickness();
-  float font_size = font_data->PlatformData().size();
-  float text_decoration_thickness_pixels =
-      FloatValueForLength(thickness_length, font_size);
-
-  return std::max(1.f, text_decoration_thickness_pixels);
-}
-
 float DoubleOffsetFromThickness(float thickness_pixels) {
   return thickness_pixels + 1.0f;
 }
@@ -281,7 +202,7 @@
 
 void TextPainterBase::PaintDecorationsExceptLineThrough(
     const TextDecorationOffsetBase& decoration_offset,
-    const DecorationInfo& decoration_info,
+    TextDecorationInfo& decoration_info,
     const PaintInfo& paint_info,
     const Vector<AppliedTextDecoration>& decorations,
     const TextPaintStyle& text_style,
@@ -295,56 +216,56 @@
 
   // text-underline-position may flip underline and overline.
   ResolvedUnderlinePosition underline_position =
-      decoration_info.underline_position;
+      decoration_info.UnderlinePosition();
   bool flip_underline_and_overline = false;
   if (underline_position == ResolvedUnderlinePosition::kOver) {
     flip_underline_and_overline = true;
     underline_position = ResolvedUnderlinePosition::kUnder;
   }
 
-  DCHECK_EQ(decorations.size(),
-            decoration_info.applied_decorations_thickness.size());
-  for (size_t applied_decorations_index = 0;
-       applied_decorations_index < decorations.size();
-       ++applied_decorations_index) {
+  for (size_t applied_decoration_index = 0;
+       applied_decoration_index < decorations.size();
+       ++applied_decoration_index) {
     const AppliedTextDecoration& decoration =
-        decorations[applied_decorations_index];
+        decorations[applied_decoration_index];
     TextDecoration lines = decoration.Lines();
     bool has_underline = EnumHasFlags(lines, TextDecoration::kUnderline);
     bool has_overline = EnumHasFlags(lines, TextDecoration::kOverline);
     if (flip_underline_and_overline)
       std::swap(has_underline, has_overline);
 
-    float resolved_thickness =
-        decoration_info
-            .applied_decorations_thickness[applied_decorations_index];
+    decoration_info.SetDecorationIndex(applied_decoration_index);
+
+    float resolved_thickness = decoration_info.ResolvedThickness();
     context.SetStrokeThickness(resolved_thickness);
 
-    if (has_underline && decoration_info.font_data) {
+    if (has_underline && decoration_info.FontData()) {
       const int paint_underline_offset =
           decoration_offset.ComputeUnderlineOffset(
-              underline_position, decoration_info.style->ComputedFontSize(),
-              decoration_info.font_data->GetFontMetrics(),
+              underline_position, decoration_info.Style().ComputedFontSize(),
+              decoration_info.FontData()->GetFontMetrics(),
               decoration.UnderlineOffset(), resolved_thickness);
-      PaintDecorationUnderOrOverLine(
-          context, decoration_info, decoration, applied_decorations_index,
-          paint_underline_offset,
-          DoubleOffsetFromThickness(resolved_thickness));
+      decoration_info.SetPerLineData(
+          TextDecoration::kUnderline, paint_underline_offset,
+          DoubleOffsetFromThickness(resolved_thickness), 1);
+      PaintDecorationUnderOrOverLine(context, decoration_info,
+                                     TextDecoration::kUnderline);
     }
 
-    if (has_overline && decoration_info.font_data) {
+    if (has_overline && decoration_info.FontData()) {
       FontVerticalPositionType position =
           flip_underline_and_overline ? FontVerticalPositionType::TopOfEmHeight
                                       : FontVerticalPositionType::TextTop;
       const int paint_overline_offset =
           decoration_offset.ComputeUnderlineOffsetForUnder(
-              decoration_info.style->TextUnderlineOffset(),
-              decoration_info.style->ComputedFontSize(), resolved_thickness,
+              decoration_info.Style().TextUnderlineOffset(),
+              decoration_info.Style().ComputedFontSize(), resolved_thickness,
               position);
-      PaintDecorationUnderOrOverLine(
-          context, decoration_info, decoration, applied_decorations_index,
-          paint_overline_offset,
-          -DoubleOffsetFromThickness(resolved_thickness));
+      decoration_info.SetPerLineData(
+          TextDecoration::kOverline, paint_overline_offset,
+          -DoubleOffsetFromThickness(resolved_thickness), 1);
+      PaintDecorationUnderOrOverLine(context, decoration_info,
+                                     TextDecoration::kOverline);
     }
 
     // We could instead build a vector of the TextDecoration instances needing
@@ -359,7 +280,7 @@
 }
 
 void TextPainterBase::PaintDecorationsOnlyLineThrough(
-    const DecorationInfo& decoration_info,
+    TextDecorationInfo& decoration_info,
     const PaintInfo& paint_info,
     const Vector<AppliedTextDecoration>& decorations,
     const TextPaintStyle& text_style) {
@@ -370,8 +291,6 @@
   if (has_combined_text_)
     context.ConcatCTM(Rotation(text_frame_rect_, kClockwise));
 
-  DCHECK_EQ(decorations.size(),
-            decoration_info.applied_decorations_thickness.size());
   for (size_t applied_decoration_index = 0;
        applied_decoration_index < decorations.size();
        ++applied_decoration_index) {
@@ -379,23 +298,25 @@
         decorations[applied_decoration_index];
     TextDecoration lines = decoration.Lines();
     if (EnumHasFlags(lines, TextDecoration::kLineThrough)) {
-      float resolved_thickness =
-          decoration_info
-              .applied_decorations_thickness[applied_decoration_index];
+      decoration_info.SetDecorationIndex(applied_decoration_index);
+
+      float resolved_thickness = decoration_info.ResolvedThickness();
       context.SetStrokeThickness(resolved_thickness);
+
       // For increased line thickness, the line-through decoration needs to grow
       // in both directions from its origin, subtract half the thickness to keep
       // it centered at the same origin.
       const float line_through_offset =
-          2 * decoration_info.baseline / 3 - resolved_thickness / 2;
+          2 * decoration_info.Baseline() / 3 - resolved_thickness / 2;
       // Floor double_offset in order to avoid double-line gap to appear
       // of different size depending on position where the double line
       // is drawn because of rounding downstream in
       // GraphicsContext::DrawLineForText.
-      AppliedDecorationPainter decoration_painter(
-          context, decoration_info, line_through_offset, decoration,
-          applied_decoration_index,
+      decoration_info.SetPerLineData(
+          TextDecoration::kLineThrough, line_through_offset,
           floorf(DoubleOffsetFromThickness(resolved_thickness)), 0);
+      AppliedDecorationPainter decoration_painter(context, decoration_info,
+                                                  TextDecoration::kLineThrough);
       // No skip: ink for line-through,
       // compare https://github.com/w3c/csswg-drafts/issues/711
       decoration_painter.Paint();
@@ -407,90 +328,19 @@
     context.ConcatCTM(Rotation(text_frame_rect_, kCounterclockwise));
 }
 
-void TextPainterBase::ComputeDecorationInfo(
-    DecorationInfo& decoration_info,
-    const PhysicalOffset& box_origin,
-    PhysicalOffset local_origin,
-    LayoutUnit width,
-    FontBaseline baseline_type,
-    const ComputedStyle& style,
-    const ComputedStyle* decorating_box_style) {
-  decoration_info.width = width;
-  decoration_info.local_origin = FloatPoint(local_origin);
-  decoration_info.antialias = ShouldSetDecorationAntialias(style);
-  decoration_info.style = &style;
-  decoration_info.baseline_type = baseline_type;
-  decoration_info.underline_position = ResolveUnderlinePosition(
-      *decoration_info.style, decoration_info.baseline_type);
-
-  decoration_info.font_data = decoration_info.style->GetFont().PrimaryFont();
-  DCHECK(decoration_info.font_data);
-  decoration_info.baseline =
-      decoration_info.font_data
-          ? decoration_info.font_data->GetFontMetrics().FloatAscent()
-          : 0;
-
-  for (const AppliedTextDecoration& decoration :
-       style.AppliedTextDecorations()) {
-    decoration_info.applied_decorations_thickness.push_back(
-        ComputeUnderlineThickness(decoration_info.underline_position,
-                                  decoration.Thickness(), style,
-                                  decorating_box_style));
-  }
-  DCHECK_EQ(style.AppliedTextDecorations().size(),
-            decoration_info.applied_decorations_thickness.size());
-}
-
-float TextPainterBase::ComputeUnderlineThickness(
-    const ResolvedUnderlinePosition& underline_position,
-    const TextDecorationThickness& applied_decoration_thickness,
-    const ComputedStyle& style,
-    const ComputedStyle* decorating_box_style) {
-  float thickness = 0;
-  if ((underline_position ==
-       ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto) ||
-      underline_position ==
-          ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont) {
-    thickness = ComputeDecorationThickness(applied_decoration_thickness, style,
-                                           style.GetFont().PrimaryFont());
-  } else {
-    // Compute decorating box. Position and thickness are computed from the
-    // decorating box.
-    // Only for non-Roman for now for the performance implications.
-    // https:// drafts.csswg.org/css-text-decor-3/#decorating-box
-    if (decorating_box_style) {
-      thickness = ComputeDecorationThickness(
-          applied_decoration_thickness, *decorating_box_style,
-          decorating_box_style->GetFont().PrimaryFont());
-    } else {
-      thickness = ComputeDecorationThickness(
-          applied_decoration_thickness, style, style.GetFont().PrimaryFont());
-    }
-  }
-  return thickness;
-}
-
 void TextPainterBase::PaintDecorationUnderOrOverLine(
     GraphicsContext& context,
-    const DecorationInfo& decoration_info,
-    const AppliedTextDecoration& decoration,
-    size_t decoration_info_thickness_index,
-    int line_offset,
-    float decoration_offset) {
-  AppliedDecorationPainter decoration_painter(
-      context, decoration_info, line_offset, decoration,
-      decoration_info_thickness_index, decoration_offset, 1);
-  if (decoration_info.style->TextDecorationSkipInk() ==
+    TextDecorationInfo& decoration_info,
+    TextDecoration line) {
+  AppliedDecorationPainter decoration_painter(context, decoration_info, line);
+  if (decoration_info.Style().TextDecorationSkipInk() ==
       ETextDecorationSkipInk::kAuto) {
-    FloatRect decoration_bounds = decoration_painter.Bounds();
+    FloatRect decoration_bounds = decoration_info.BoundsForLine(line);
     ClipDecorationsStripe(
-        -decoration_info.baseline + decoration_bounds.Y() -
-            decoration_info.local_origin.Y(),
+        decoration_info.InkSkipClipUpper(decoration_bounds.Y()),
         decoration_bounds.Height(),
-        std::min(
-            decoration_info
-                .applied_decorations_thickness[decoration_info_thickness_index],
-            kDecorationClipMaxDilation));
+        std::min(decoration_info.ResolvedThickness(),
+                 kDecorationClipMaxDilation));
   }
   decoration_painter.Paint();
 }
diff --git a/third_party/blink/renderer/core/paint/text_painter_base.h b/third_party/blink/renderer/core/paint/text_painter_base.h
index 4904fc8a..15ce554 100644
--- a/third_party/blink/renderer/core/paint/text_painter_base.h
+++ b/third_party/blink/renderer/core/paint/text_painter_base.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
-#include "third_party/blink/renderer/core/paint/decoration_info.h"
+#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/core/paint/text_paint_style.h"
 #include "third_party/blink/renderer/core/style/applied_text_decoration.h"
 #include "third_party/blink/renderer/core/style/text_decoration_thickness.h"
@@ -53,35 +53,18 @@
                                     GraphicsContextStateSaver&);
 
   void PaintDecorationsExceptLineThrough(const TextDecorationOffsetBase&,
-                                         const DecorationInfo&,
+                                         TextDecorationInfo&,
                                          const PaintInfo&,
                                          const Vector<AppliedTextDecoration>&,
                                          const TextPaintStyle& text_style,
                                          bool* has_line_through_decoration);
-  void PaintDecorationsOnlyLineThrough(const DecorationInfo&,
+  void PaintDecorationsOnlyLineThrough(TextDecorationInfo&,
                                        const PaintInfo&,
                                        const Vector<AppliedTextDecoration>&,
                                        const TextPaintStyle&);
   void PaintDecorationUnderOrOverLine(GraphicsContext&,
-                                      const DecorationInfo&,
-                                      const AppliedTextDecoration&,
-                                      size_t decoration_info_thickness_index,
-                                      int line_offset,
-                                      float decoration_offset);
-
-  void ComputeDecorationInfo(DecorationInfo&,
-                             const PhysicalOffset& box_origin,
-                             PhysicalOffset local_origin,
-                             LayoutUnit width,
-                             FontBaseline,
-                             const ComputedStyle&,
-                             const ComputedStyle* decorating_box_style);
-
-  float ComputeUnderlineThickness(
-      const ResolvedUnderlinePosition& underline_position,
-      const TextDecorationThickness& applied_decoration_thickness,
-      const ComputedStyle&,
-      const ComputedStyle* decorating_box_style);
+                                      TextDecorationInfo&,
+                                      TextDecoration line);
 
   static Color TextColorForWhiteBackground(Color);
   static TextPaintStyle TextPaintingStyle(const Document&,
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc b/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
index 9c5145c..76d204b 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
@@ -123,9 +123,7 @@
   IDBObjectStore* object_store = EffectiveObjectStore();
   return object_store->DoPut(script_state, mojom::IDBPutMode::CursorUpdate,
                              IDBRequest::Source::FromIDBCursor(this), value,
-                             IdbPrimaryKey(), exception_state,
-                             /*optional_custom_callback=*/nullptr,
-                             /*blob_handles_out=*/nullptr);
+                             IdbPrimaryKey(), exception_state);
 }
 
 void IDBCursor::advance(unsigned count, ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc b/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
index ac684b1c..231d68c 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
@@ -47,7 +47,6 @@
 #include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h"
-#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h"
 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -354,9 +353,7 @@
   IDB_TRACE1("IDBObjectStore::addRequestSetup", "store_name",
              metadata_->name.Utf8());
   return DoPut(script_state, mojom::IDBPutMode::AddOnly, value, key,
-               exception_state,
-               /*optional_custom_callback=*/nullptr,
-               /*blob_handles_out=*/nullptr);
+               exception_state);
 }
 
 IDBRequest* IDBObjectStore::put(ScriptState* script_state,
@@ -367,171 +364,20 @@
              exception_state);
 }
 
-namespace {
-
-class PutAllWebCallbacksAccumulationImpl
-    : public base::RefCounted<PutAllWebCallbacksAccumulationImpl> {
- public:
-  PutAllWebCallbacksAccumulationImpl(
-      int num_custom_callbacks,
-      std::unique_ptr<WebIDBCallbacks> request_callbacks)
-      : request_callbacks_(std::move(request_callbacks)),
-        num_custom_callbacks_(num_custom_callbacks) {}
-
-  void HandleCustomCallbackSuccess() {
-    DCHECK_GT(num_custom_callbacks_, 0);
-    num_custom_callbacks_--;
-    if (num_custom_callbacks_ == 0)
-      CallRequestCallbacks();
-  }
-
-  void HandleCustomCallbackError(mojom::blink::IDBException code,
-                                 const String& message) {
-    DCHECK_GT(num_custom_callbacks_, 0);
-    num_custom_callbacks_--;
-    received_error_ = true;
-    latest_error_code = code;
-    latest_error_message = message;
-    if (num_custom_callbacks_ == 0)
-      CallRequestCallbacks();
-  }
-
-  void CallRequestCallbacks() {
-    if (!received_error_) {
-      request_callbacks_->Success();
-    } else {
-      request_callbacks_->Error(latest_error_code, latest_error_message);
-    }
-  }
-
- private:
-  friend class base::RefCounted<PutAllWebCallbacksAccumulationImpl>;
-  ~PutAllWebCallbacksAccumulationImpl() = default;
-
-  std::unique_ptr<WebIDBCallbacks> request_callbacks_;
-  int num_custom_callbacks_;
-  bool received_error_ = false;
-  mojom::blink::IDBException latest_error_code;
-  String latest_error_message;
-};
-
-class PutAllWebCallbacksImpl : public WebIDBCallbacks {
- public:
-  explicit PutAllWebCallbacksImpl(
-      scoped_refptr<PutAllWebCallbacksAccumulationImpl> callback_accumulator)
-      : callback_accumulator_(callback_accumulator) {}
-
-  void Success() override { NOTREACHED(); }
-
-  void Error(mojom::blink::IDBException code, const String& message) override {
-    callback_accumulator_->HandleCustomCallbackError(code, message);
-  }
-
-  void SetState(base::WeakPtr<WebIDBCursorImpl> cursor,
-                int64_t transaction_id) override {}
-
-  void SuccessNamesAndVersionsList(
-      Vector<mojom::blink::IDBNameAndVersionPtr> names_and_versions) override {
-    NOTREACHED();
-  }
-
-  void SuccessStringList(const Vector<String>&) override { NOTREACHED(); }
-
-  void SuccessCursor(
-      mojo::PendingAssociatedRemote<mojom::blink::IDBCursor> cursor_info,
-      std::unique_ptr<IDBKey> key,
-      std::unique_ptr<IDBKey> primary_key,
-      base::Optional<std::unique_ptr<IDBValue>> optional_value) override {
-    NOTREACHED();
-  }
-
-  void SuccessCursorPrefetch(
-      Vector<std::unique_ptr<IDBKey>> keys,
-      Vector<std::unique_ptr<IDBKey>> primary_keys,
-      Vector<std::unique_ptr<IDBValue>> values) override {
-    NOTREACHED();
-  }
-
-  void SuccessDatabase(
-      mojo::PendingAssociatedRemote<mojom::blink::IDBDatabase> pending_backend,
-      const IDBDatabaseMetadata& metadata) override {
-    NOTREACHED();
-  }
-
-  void SuccessKey(std::unique_ptr<IDBKey> key) override {
-    callback_accumulator_->HandleCustomCallbackSuccess();
-  }
-
-  void SuccessValue(mojom::blink::IDBReturnValuePtr return_value) override {
-    NOTREACHED();
-  }
-
-  void SuccessArray(Vector<mojom::blink::IDBReturnValuePtr> values) override {
-    NOTREACHED();
-  }
-
-  void SuccessInteger(int64_t value) override { NOTREACHED(); }
-
-  void SuccessCursorContinue(
-      std::unique_ptr<IDBKey> key,
-      std::unique_ptr<IDBKey> primary_key,
-      base::Optional<std::unique_ptr<IDBValue>> value) override {
-    NOTREACHED();
-  }
-
-  void Blocked(int64_t old_version) override { NOTREACHED(); }
-
-  void UpgradeNeeded(
-      mojo::PendingAssociatedRemote<mojom::blink::IDBDatabase> pending_database,
-      int64_t old_version,
-      mojom::IDBDataLoss data_loss,
-      const String& data_loss_message,
-      const IDBDatabaseMetadata& metadata) override {
-    NOTREACHED();
-  }
-
-  void DetachRequestFromCallback() override { NOTREACHED(); }
-
-  void ReceiveGetAllResults(
-      bool key_only,
-      mojo::PendingReceiver<mojom::blink::IDBDatabaseGetAllResultSink> receiver)
-      override {
-    NOTREACHED();
-  }
-
- private:
-  scoped_refptr<PutAllWebCallbacksAccumulationImpl> callback_accumulator_;
-};
-
-}  // namespace
-
-IDBRequest* IDBObjectStore::putAll(ScriptState* script_state,
-                                   const HeapVector<ScriptValue>& values,
-                                   ExceptionState& exception_state) {
+HeapVector<Member<IDBRequest>> IDBObjectStore::putAll(
+    ScriptState* script_state,
+    const HeapVector<ScriptValue>& values,
+    ExceptionState& exception_state) {
   v8::Isolate* isolate = script_state->GetIsolate();
   const ScriptValue& v8_undefined =
       ScriptValue(isolate, v8::Undefined(isolate));
-  IDBRequest::AsyncTraceState metrics("IDBObjectStore::putAll");
-  IDBRequest* request = IDBRequest::Create(
-      script_state, this, transaction_.Get(), std::move(metrics));
-  std::unique_ptr<WebIDBCallbacks> request_callbacks =
-      request->CreateWebCallbacks();
-  scoped_refptr<PutAllWebCallbacksAccumulationImpl> callback_accumulator =
-      base::MakeRefCounted<PutAllWebCallbacksAccumulationImpl>(
-          values.size(), std::move(request_callbacks));
+  HeapVector<Member<IDBRequest>> requests;
   for (const auto& value : values) {
-    std::unique_ptr<WebIDBCallbacks> custom_callback =
-        std::make_unique<PutAllWebCallbacksImpl>(callback_accumulator);
-    Vector<scoped_refptr<BlobDataHandle>> blob_handles_out;
     IDBRequest* result =
-        DoPut(script_state, mojom::IDBPutMode::AddOrUpdate, value, v8_undefined,
-              exception_state, std::move(custom_callback), &blob_handles_out);
-    for (const auto& blob_handle : blob_handles_out) {
-      request->transit_blob_handles().push_back(blob_handle);
-    }
-    DCHECK(result == nullptr);
+        put(script_state, value, v8_undefined, exception_state);
+    requests.push_back(*result);
   }
-  return request;
+  return requests;
 }
 
 IDBRequest* IDBObjectStore::put(ScriptState* script_state,
@@ -541,19 +387,14 @@
   IDB_TRACE1("IDBObjectStore::putRequestSetup", "store_name",
              metadata_->name.Utf8());
   return DoPut(script_state, mojom::IDBPutMode::AddOrUpdate, value, key,
-               exception_state,
-               /*optional_custom_callback=*/nullptr,
-               /*blob_handles_out=*/nullptr);
+               exception_state);
 }
 
-IDBRequest* IDBObjectStore::DoPut(
-    ScriptState* script_state,
-    mojom::IDBPutMode put_mode,
-    const ScriptValue& value,
-    const ScriptValue& key_value,
-    ExceptionState& exception_state,
-    std::unique_ptr<WebIDBCallbacks> optional_custom_callback,
-    Vector<scoped_refptr<BlobDataHandle>>* blob_handles_out) {
+IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state,
+                                  mojom::IDBPutMode put_mode,
+                                  const ScriptValue& value,
+                                  const ScriptValue& key_value,
+                                  ExceptionState& exception_state) {
   std::unique_ptr<IDBKey> key =
       key_value.IsUndefined()
           ? nullptr
@@ -561,22 +402,17 @@
                 script_state->GetIsolate(), key_value, exception_state);
   if (exception_state.HadException())
     return nullptr;
-
   return DoPut(script_state, put_mode,
                IDBRequest::Source::FromIDBObjectStore(this), value, key.get(),
-               exception_state, std::move(optional_custom_callback),
-               blob_handles_out);
+               exception_state);
 }
 
-IDBRequest* IDBObjectStore::DoPut(
-    ScriptState* script_state,
-    mojom::IDBPutMode put_mode,
-    const IDBRequest::Source& source,
-    const ScriptValue& value,
-    const IDBKey* key,
-    ExceptionState& exception_state,
-    std::unique_ptr<WebIDBCallbacks> optional_custom_callback,
-    Vector<scoped_refptr<BlobDataHandle>>* blob_handles_out) {
+IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state,
+                                  mojom::IDBPutMode put_mode,
+                                  const IDBRequest::Source& source,
+                                  const ScriptValue& value,
+                                  const IDBKey* key,
+                                  ExceptionState& exception_state) {
   const char* tracing_name = nullptr;
   switch (put_mode) {
     case mojom::IDBPutMode::AddOrUpdate:
@@ -760,11 +596,8 @@
       base::saturated_cast<base::HistogramBase::Sample>(
           value_wrapper.DataLengthBeforeWrapInBytes() / 1024));
 
-  IDBRequest* request = nullptr;
-  if (!optional_custom_callback) {
-    request = IDBRequest::Create(script_state, source, transaction_.Get(),
-                                 std::move(metrics));
-  }
+  IDBRequest* request = IDBRequest::Create(
+      script_state, source, transaction_.Get(), std::move(metrics));
 
   value_wrapper.DoneCloning();
 
@@ -774,18 +607,11 @@
       value_wrapper.TakeWireBytes(), value_wrapper.TakeBlobInfo(),
       value_wrapper.TakeNativeFileSystemTransferTokens());
 
-  std::unique_ptr<WebIDBCallbacks> callbacks;
-  if (optional_custom_callback) {
-    *blob_handles_out = value_wrapper.TakeBlobDataHandles();
-    callbacks = std::move(optional_custom_callback);
-  } else {
-    request->transit_blob_handles() = value_wrapper.TakeBlobDataHandles();
-    callbacks = request->CreateWebCallbacks();
-  }
-
+  request->transit_blob_handles() = value_wrapper.TakeBlobDataHandles();
   transaction_->transaction_backend()->Put(
       Id(), std::move(idb_value), IDBKey::Clone(key), put_mode,
-      std::move(callbacks), std::move(index_keys));
+      base::WrapUnique(request->CreateWebCallbacks().release()),
+      std::move(index_keys));
 
   return request;
 }
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_object_store.h b/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
index ca85f63..58353ab 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
@@ -102,9 +102,9 @@
                   const ScriptValue& key,
                   ExceptionState&);
   IDBRequest* put(ScriptState*, const ScriptValue& value, ExceptionState&);
-  IDBRequest* putAll(ScriptState*,
-                     const HeapVector<ScriptValue>& values,
-                     ExceptionState&);
+  HeapVector<Member<IDBRequest>> putAll(ScriptState*,
+                                        const HeapVector<ScriptValue>& values,
+                                        ExceptionState&);
   IDBRequest* put(ScriptState*,
                   const ScriptValue& value,
                   const ScriptValue& key,
@@ -131,9 +131,7 @@
                     const IDBRequest::Source&,
                     const ScriptValue&,
                     const IDBKey*,
-                    ExceptionState&,
-                    std::unique_ptr<WebIDBCallbacks> optional_custom_callback,
-                    Vector<scoped_refptr<BlobDataHandle>>* blob_handles_out);
+                    ExceptionState&);
 
   // Used internally and by InspectorIndexedDBAgent:
   IDBRequest* openCursor(
@@ -209,9 +207,7 @@
                     mojom::IDBPutMode,
                     const ScriptValue&,
                     const ScriptValue& key_value,
-                    ExceptionState&,
-                    std::unique_ptr<WebIDBCallbacks> optional_custom_callback,
-                    Vector<scoped_refptr<BlobDataHandle>>* blob_handles_out);
+                    ExceptionState&);
 
   int64_t FindIndexId(const String& name) const;
 
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl b/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
index 844774e..275241c 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
+++ b/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
@@ -42,7 +42,7 @@
       MeasureAs=IndexedDBWrite,
       RaisesException,
       RuntimeEnabled=IDBPutAll
-    ] IDBRequest putAll(sequence<any> values);
+    ] sequence<IDBRequest> putAll(sequence<any> values);
 
     [CallWith=ScriptState, MeasureAs=IndexedDBWrite, NewObject, RaisesException]
     IDBRequest add(any value, optional any key);
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
index a324546..cd00271 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -30,6 +30,7 @@
 
 #include "third_party/blink/renderer/modules/websockets/websocket_channel_impl.h"
 
+#include <string.h>
 #include <memory>
 
 #include "base/callback.h"
@@ -106,38 +107,6 @@
   std::unique_ptr<FileReaderLoader> loader_;
 };
 
-class WebSocketChannelImpl::Message final
-    : public GarbageCollected<WebSocketChannelImpl::Message> {
- public:
-  using DidCallSendMessage =
-      util::StrongAlias<class DidCallSendMessageTag, bool>;
-  Message(const std::string&,
-          base::OnceClosure completion_callback,
-          DidCallSendMessage did_call_send_message);
-  explicit Message(scoped_refptr<BlobDataHandle>);
-  Message(DOMArrayBuffer*,
-          base::OnceClosure completion_callback,
-          DidCallSendMessage did_call_send_message);
-  Message(MessageType type,
-          base::span<const char> message,
-          base::OnceClosure completion_callback);
-  // Close message
-  Message(uint16_t code, const String& reason);
-
-  void Trace(Visitor* visitor) const { visitor->Trace(array_buffer); }
-
-  MessageType type;
-
-  std::string text;
-  scoped_refptr<BlobDataHandle> blob_data_handle;
-  Member<DOMArrayBuffer> array_buffer;
-  base::span<const char> pending_payload;
-  DidCallSendMessage did_call_send_message = DidCallSendMessage(false);
-  uint16_t code;
-  String reason;
-  base::OnceClosure completion_callback;
-};
-
 WebSocketChannelImpl::BlobLoader::BlobLoader(
     scoped_refptr<BlobDataHandle> blob_data_handle,
     WebSocketChannelImpl* channel,
@@ -324,10 +293,10 @@
     }
   }
 
-  messages_.push_back(MakeGarbageCollected<Message>(
-      message.substr(message.size() - data.size(), data.size()),
-      std::move(completion_callback),
-      Message::DidCallSendMessage(did_attempt_to_send)));
+  messages_.push_back(
+      Message(message.substr(message.size() - data.size(), data.size()),
+              std::move(completion_callback),
+              Message::DidCallSendMessage(did_attempt_to_send)));
 
   // ProcessSendQueue() will do nothing when MaybeSendSynchronously() is called.
   ProcessSendQueue();
@@ -350,8 +319,7 @@
   // affect actual behavior.
   probe::DidSendWebSocketMessage(execution_context_, identifier_,
                                  WebSocketOpCode::kOpCodeBinary, true, "", 0);
-  messages_.push_back(
-      MakeGarbageCollected<Message>(std::move(blob_data_handle)));
+  messages_.push_back(Message(std::move(blob_data_handle)));
   ProcessSendQueue();
 }
 
@@ -376,15 +344,11 @@
             network::mojom::blink::WebSocketMessageType::BINARY, &message)) {
       return SendResult::SENT_SYNCHRONOUSLY;
     }
-    byte_offset += byte_length - message.size();
-    byte_length = message.size();
   }
 
-  // buffer.Slice copies its contents.
-  messages_.push_back(MakeGarbageCollected<Message>(
-      buffer.Slice(byte_offset, byte_offset + byte_length),
-      std::move(completion_callback),
-      Message::DidCallSendMessage(did_attempt_to_send)));
+  messages_.push_back(
+      Message(message, std::move(completion_callback),
+              Message::DidCallSendMessage(did_attempt_to_send)));
 
   // ProcessSendQueue() will do nothing when MaybeSendSynchronously() is called.
   ProcessSendQueue();
@@ -401,7 +365,7 @@
   NETWORK_DVLOG(1) << this << " Close(" << code << ", " << reason << ")";
   uint16_t code_to_send = static_cast<uint16_t>(
       code == kCloseEventCodeNotSpecified ? kCloseEventCodeNoStatusRcvd : code);
-  messages_.push_back(MakeGarbageCollected<Message>(code_to_send, reason));
+  messages_.push_back(Message(code_to_send, reason));
   ProcessSendQueue();
 }
 
@@ -587,7 +551,6 @@
 
 void WebSocketChannelImpl::Trace(Visitor* visitor) const {
   visitor->Trace(blob_loader_);
-  visitor->Trace(messages_);
   visitor->Trace(client_);
   visitor->Trace(execution_context_);
   visitor->Trace(websocket_);
@@ -599,36 +562,43 @@
 WebSocketChannelImpl::Message::Message(const std::string& text,
                                        base::OnceClosure completion_callback,
                                        DidCallSendMessage did_call_send_message)
-    : type(kMessageTypeText),
-      text(text),
-      pending_payload(this->text),
-      did_call_send_message(did_call_send_message),
-      completion_callback(std::move(completion_callback)) {}
+    : message_data_(CreateMessageData(text.length())),
+      type_(kMessageTypeText),
+      did_call_send_message_(did_call_send_message),
+      completion_callback_(std::move(completion_callback)) {
+  memcpy(message_data_.get(), text.data(), text.length());
+  pending_payload_ = base::make_span(message_data_.get(), text.length());
+}
 
 WebSocketChannelImpl::Message::Message(
     scoped_refptr<BlobDataHandle> blob_data_handle)
-    : type(kMessageTypeBlob), blob_data_handle(std::move(blob_data_handle)) {}
+    : type_(kMessageTypeBlob), blob_data_handle_(std::move(blob_data_handle)) {}
 
-WebSocketChannelImpl::Message::Message(DOMArrayBuffer* array_buffer,
+WebSocketChannelImpl::Message::Message(base::span<const char> message,
                                        base::OnceClosure completion_callback,
                                        DidCallSendMessage did_call_send_message)
-    : type(kMessageTypeArrayBuffer),
-      array_buffer(array_buffer),
-      pending_payload(
-          base::make_span(static_cast<const char*>(array_buffer->Data()),
-                          array_buffer->ByteLengthAsSizeT())),
-      did_call_send_message(did_call_send_message),
-      completion_callback(std::move(completion_callback)) {}
+    : message_data_(CreateMessageData(message.size())),
+      type_(kMessageTypeArrayBuffer),
+      did_call_send_message_(did_call_send_message),
+      completion_callback_(std::move(completion_callback)) {
+  memcpy(message_data_.get(), message.data(), message.size());
+  pending_payload_ = base::make_span(message_data_.get(), message.size());
+}
 
 WebSocketChannelImpl::Message::Message(uint16_t code, const String& reason)
-    : type(kMessageTypeClose), code(code), reason(reason) {}
+    : type_(kMessageTypeClose), code_(code), reason_(reason) {}
 
 WebSocketChannelImpl::Message::Message(MessageType type,
                                        base::span<const char> pending_payload,
                                        base::OnceClosure completion_callback)
-    : type(type),
-      pending_payload(pending_payload),
-      completion_callback(std::move(completion_callback)) {}
+    : type_(type),
+      pending_payload_(pending_payload),
+      completion_callback_(std::move(completion_callback)) {}
+
+WebSocketChannelImpl::Message::Message(Message&&) = default;
+
+WebSocketChannelImpl::Message& WebSocketChannelImpl::Message::operator=(
+    Message&&) = default;
 
 WebSocketChannelImpl::State WebSocketChannelImpl::GetState() const {
   if (!has_initiated_opening_handshake_) {
@@ -643,6 +613,41 @@
   return State::kDisconnected;
 }
 
+WebSocketChannelImpl::MessageType WebSocketChannelImpl::Message::Type() const {
+  return type_;
+}
+
+scoped_refptr<BlobDataHandle>
+WebSocketChannelImpl::Message::GetBlobDataHandle() {
+  return blob_data_handle_;
+}
+
+base::span<const char>& WebSocketChannelImpl::Message::MutablePendingPayload() {
+  return pending_payload_;
+}
+
+WebSocketChannelImpl::Message::DidCallSendMessage
+WebSocketChannelImpl::Message::GetDidCallSendMessage() const {
+  return did_call_send_message_;
+}
+
+void WebSocketChannelImpl::Message::SetDidCallSendMessage(
+    WebSocketChannelImpl::Message::DidCallSendMessage did_call_send_message) {
+  did_call_send_message_ = did_call_send_message;
+}
+
+uint16_t WebSocketChannelImpl::Message::Code() const {
+  return code_;
+}
+
+String WebSocketChannelImpl::Message::Reason() const {
+  return reason_;
+}
+
+base::OnceClosure WebSocketChannelImpl::Message::CompletionCallback() {
+  return std::move(completion_callback_);
+}
+
 bool WebSocketChannelImpl::MaybeSendSynchronously(
     network::mojom::blink::WebSocketMessageType frame_type,
     base::span<const char>* data) {
@@ -657,24 +662,23 @@
   // TODO(yhirano): This should be DCHECK_EQ(GetState(), State::kOpen).
   DCHECK(GetState() == State::kOpen || GetState() == State::kConnecting);
   while (!messages_.IsEmpty() && !blob_loader_ && !wait_for_writable_) {
-    Message* message = messages_.front().Get();
+    Message& message = messages_.front();
     network::mojom::blink::WebSocketMessageType message_type =
         network::mojom::blink::WebSocketMessageType::BINARY;
-    CHECK(message);
-    switch (message->type) {
+    switch (message.Type()) {
       case kMessageTypeText:
         message_type = network::mojom::blink::WebSocketMessageType::TEXT;
         FALLTHROUGH;
       case kMessageTypeArrayBuffer: {
-        base::span<const char>& data_frame = message->pending_payload;
-        if (!message->did_call_send_message) {
+        base::span<const char>& data_frame = message.MutablePendingPayload();
+        if (!message.GetDidCallSendMessage()) {
           websocket_->SendMessage(message_type, data_frame.size());
-          message->did_call_send_message = Message::DidCallSendMessage(true);
+          message.SetDidCallSendMessage(Message::DidCallSendMessage(true));
         }
         if (!SendMessageData(&data_frame))
           return;
         base::OnceClosure completion_callback =
-            std::move(messages_.front()->completion_callback);
+            messages_.front().CompletionCallback();
         if (!completion_callback.is_null())
           std::move(completion_callback).Run();
         messages_.pop_front();
@@ -682,10 +686,9 @@
       }
       case kMessageTypeBlob:
         CHECK(!blob_loader_);
-        CHECK(message);
-        CHECK(message->blob_data_handle);
+        CHECK(message.GetBlobDataHandle());
         blob_loader_ = MakeGarbageCollected<BlobLoader>(
-            message->blob_data_handle, this, file_reading_task_runner_);
+            message.GetBlobDataHandle(), this, file_reading_task_runner_);
         break;
       case kMessageTypeClose: {
         // No message should be sent from now on.
@@ -693,8 +696,8 @@
         DCHECK_EQ(sent_size_of_top_message_, 0u);
         handshake_throttle_.reset();
         websocket_->StartClosingHandshake(
-            message->code,
-            message->reason.IsNull() ? g_empty_string : message->reason);
+            message.Code(),
+            message.Reason().IsNull() ? g_empty_string : message.Reason());
         messages_.pop_front();
         break;
       }
@@ -784,10 +787,13 @@
   blob_loader_.Clear();
   // The loaded blob is always placed on |messages_[0]|.
   DCHECK_GT(messages_.size(), 0u);
-  DCHECK_EQ(messages_.front()->type, kMessageTypeBlob);
+  DCHECK_EQ(messages_.front().Type(), kMessageTypeBlob);
+
   // We replace it with the loaded blob.
-  messages_.front() = MakeGarbageCollected<Message>(
-      buffer, base::OnceClosure(), Message::DidCallSendMessage(false));
+  messages_.front() =
+      Message(base::make_span(static_cast<const char*>(buffer->Data()),
+                              buffer->ByteLengthAsSizeT()),
+              base::OnceClosure(), Message::DidCallSendMessage(false));
 
   ProcessSendQueue();
 }
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
index a9a4be7..4a91934 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -172,6 +172,74 @@
     Vector<char> data;
   };
 
+  class Message final {
+    DISALLOW_NEW();
+
+   public:
+    using DidCallSendMessage =
+        util::StrongAlias<class DidCallSendMessageTag, bool>;
+
+    // Initializes message as a string
+    Message(const std::string&,
+            base::OnceClosure completion_callback,
+            DidCallSendMessage did_call_send_message);
+
+    // Initializes message as a blob
+    explicit Message(scoped_refptr<BlobDataHandle>);
+
+    // Initializes message as a ArrayBuffer
+    Message(base::span<const char> message,
+            base::OnceClosure completion_callback,
+            DidCallSendMessage did_call_send_message);
+
+    // Initializes a Blank message
+    Message(MessageType type,
+            base::span<const char> message,
+            base::OnceClosure completion_callback);
+
+    // Close message
+    Message(uint16_t code, const String& reason);
+
+    Message(const Message&) = delete;
+    Message& operator=(const Message&) = delete;
+
+    Message(Message&&);
+    Message& operator=(Message&&);
+
+    MessageType Type() const;
+    scoped_refptr<BlobDataHandle> GetBlobDataHandle();
+    DidCallSendMessage GetDidCallSendMessage() const;
+    uint16_t Code() const;
+    String Reason() const;
+    base::OnceClosure CompletionCallback();
+
+    // Returns a mutable |pending_payload_|. Since calling code always mutates
+    // the value, |pending_payload_| only has a mutable getter.
+    base::span<const char>& MutablePendingPayload();
+
+    void SetDidCallSendMessage(DidCallSendMessage did_call_send_message);
+
+   private:
+    struct MessageDataDeleter {
+      void operator()(char* p) const { WTF::Partitions::FastFree(p); }
+    };
+    using MessageData = std::unique_ptr<char[], MessageDataDeleter>;
+    static MessageData CreateMessageData(std::size_t message_size) {
+      return MessageData(static_cast<char*>(WTF::Partitions::FastMalloc(
+          message_size, "blink::WebSockChannelImpl::Message::MessageData")));
+    }
+
+    MessageData message_data_;
+    MessageType type_;
+
+    scoped_refptr<BlobDataHandle> blob_data_handle_;
+    base::span<const char> pending_payload_;
+    DidCallSendMessage did_call_send_message_ = DidCallSendMessage(false);
+    uint16_t code_ = 0;
+    String reason_;
+    base::OnceClosure completion_callback_;
+  };
+
   // The state is defined to see the conceptual state more clearly than checking
   // various members (for DCHECKs for example). This is only used internally.
   enum class State {
@@ -233,7 +301,7 @@
   KURL url_;
   uint64_t identifier_;
   Member<BlobLoader> blob_loader_;
-  HeapDeque<Member<Message>> messages_;
+  WTF::Deque<Message> messages_;
   WebSocketMessageChunkAccumulator message_chunks_;
   const Member<ExecutionContext> execution_context_;
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index c042b23..3fb1bc22 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -714,11 +714,11 @@
   return context_provider_wrapper_;
 }
 
-// CanvasResourceWebGPUSharedImage
+// CanvasResourceSkiaDawnSharedImage
 //==============================================================================
 
 #if BUILDFLAG(SKIA_USE_DAWN)
-CanvasResourceWebGPUSharedImage::CanvasResourceWebGPUSharedImage(
+CanvasResourceSkiaDawnSharedImage::CanvasResourceSkiaDawnSharedImage(
     const IntSize& size,
     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
     base::WeakPtr<CanvasResourceProvider> provider,
@@ -768,8 +768,8 @@
   owning_thread_data().shared_image_mailbox = shared_image_mailbox;
 }
 
-scoped_refptr<CanvasResourceWebGPUSharedImage>
-CanvasResourceWebGPUSharedImage::Create(
+scoped_refptr<CanvasResourceSkiaDawnSharedImage>
+CanvasResourceSkiaDawnSharedImage::Create(
     const IntSize& size,
     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
     base::WeakPtr<CanvasResourceProvider> provider,
@@ -777,19 +777,19 @@
     const CanvasColorParams& color_params,
     bool is_origin_top_left,
     uint32_t shared_image_usage_flags) {
-  TRACE_EVENT0("blink", "CanvasResourceWebGPUSharedImage::Create");
-  auto resource = base::AdoptRef(new CanvasResourceWebGPUSharedImage(
+  TRACE_EVENT0("blink", "CanvasResourceSkiaDawnSharedImage::Create");
+  auto resource = base::AdoptRef(new CanvasResourceSkiaDawnSharedImage(
       size, std::move(context_provider_wrapper), std::move(provider),
       filter_quality, color_params, is_origin_top_left,
       shared_image_usage_flags));
   return resource->IsValid() ? resource : nullptr;
 }
 
-bool CanvasResourceWebGPUSharedImage::IsValid() const {
+bool CanvasResourceSkiaDawnSharedImage::IsValid() const {
   return !mailbox().IsZero();
 }
 
-GLenum CanvasResourceWebGPUSharedImage::TextureTarget() const {
+GLenum CanvasResourceSkiaDawnSharedImage::TextureTarget() const {
 #if defined(OS_MAC)
   return GL_TEXTURE_RECTANGLE_ARB;
 #else
@@ -797,11 +797,11 @@
 #endif
 }
 
-CanvasResourceWebGPUSharedImage::~CanvasResourceWebGPUSharedImage() {
+CanvasResourceSkiaDawnSharedImage::~CanvasResourceSkiaDawnSharedImage() {
   OnDestroy();
 }
 
-void CanvasResourceWebGPUSharedImage::TearDown() {
+void CanvasResourceSkiaDawnSharedImage::TearDown() {
   DCHECK(!is_cross_thread());
 
   if (ContextProviderWrapper()) {
@@ -817,7 +817,7 @@
   }
 }
 
-void CanvasResourceWebGPUSharedImage::Abandon() {
+void CanvasResourceSkiaDawnSharedImage::Abandon() {
   if (auto context_provider = SharedGpuContext::ContextProviderWrapper()) {
     auto* sii = context_provider->ContextProvider()->SharedImageInterface();
     if (sii)
@@ -825,14 +825,14 @@
   }
 }
 
-void CanvasResourceWebGPUSharedImage::WillDraw() {
+void CanvasResourceSkiaDawnSharedImage::WillDraw() {
   DCHECK(!is_cross_thread())
       << "Write access is only allowed on the owning thread";
 
   owning_thread_data().mailbox_needs_new_sync_token = true;
 }
 
-void CanvasResourceWebGPUSharedImage::BeginAccess() {
+void CanvasResourceSkiaDawnSharedImage::BeginAccess() {
   auto* webgpu = WebGPUInterface();
   gpu::webgpu::ReservedTexture reservation =
       webgpu->ReserveTexture(kWebGPUDeviceClientID);
@@ -849,7 +849,7 @@
       reinterpret_cast<GLbyte*>(&owning_thread_data().shared_image_mailbox));
 }
 
-void CanvasResourceWebGPUSharedImage::EndAccess() {
+void CanvasResourceSkiaDawnSharedImage::EndAccess() {
   auto* webgpu = WebGPUInterface();
   webgpu->FlushCommands();
   webgpu->DissociateMailbox(kWebGPUDeviceClientID, owning_thread_data().id,
@@ -860,7 +860,7 @@
   owning_thread_data().generation = 0;
 }
 
-GrBackendTexture CanvasResourceWebGPUSharedImage::CreateGrTexture() const {
+GrBackendTexture CanvasResourceSkiaDawnSharedImage::CreateGrTexture() const {
   GrDawnTextureInfo info = {};
   info.fTexture = texture();
 #if defined(OS_MAC)
@@ -872,14 +872,14 @@
   return GrBackendTexture(Size().Width(), Size().Height(), info);
 }
 
-void CanvasResourceWebGPUSharedImage::CopyRenderingResultsToGpuMemoryBuffer(
+void CanvasResourceSkiaDawnSharedImage::CopyRenderingResultsToGpuMemoryBuffer(
     const sk_sp<SkImage>&) {
   DCHECK(false);
 }
 
 // static
-void CanvasResourceWebGPUSharedImage::OnBitmapImageDestroyed(
-    scoped_refptr<CanvasResourceWebGPUSharedImage> resource,
+void CanvasResourceSkiaDawnSharedImage::OnBitmapImageDestroyed(
+    scoped_refptr<CanvasResourceSkiaDawnSharedImage> resource,
     bool has_read_ref_on_texture,
     const gpu::SyncToken& sync_token,
     bool is_lost) {
@@ -888,7 +888,7 @@
     PostCrossThreadTask(
         task_runner, FROM_HERE,
         CrossThreadBindOnce(
-            &CanvasResourceWebGPUSharedImage::OnBitmapImageDestroyed,
+            &CanvasResourceSkiaDawnSharedImage::OnBitmapImageDestroyed,
             std::move(resource), has_read_ref_on_texture, sync_token, is_lost));
     return;
   }
@@ -909,7 +909,7 @@
                         sync_token, is_lost);
 }
 
-void CanvasResourceWebGPUSharedImage::Transfer() {
+void CanvasResourceSkiaDawnSharedImage::Transfer() {
   if (is_cross_thread() || !ContextProviderWrapper())
     return;
 
@@ -920,8 +920,8 @@
   GetSyncToken();
 }
 
-scoped_refptr<StaticBitmapImage> CanvasResourceWebGPUSharedImage::Bitmap() {
-  TRACE_EVENT0("blink", "CanvasResourceWebGPUSharedImage::Bitmap");
+scoped_refptr<StaticBitmapImage> CanvasResourceSkiaDawnSharedImage::Bitmap() {
+  TRACE_EVENT0("blink", "CanvasResourceSkiaDawnSharedImage::Bitmap");
 
   SkImageInfo image_info = CreateSkImageInfo();
 
@@ -949,7 +949,7 @@
   // resource once all refs have been released.
   auto release_callback = viz::SingleReleaseCallback::Create(
       base::BindOnce(&OnBitmapImageDestroyed,
-                     scoped_refptr<CanvasResourceWebGPUSharedImage>(this),
+                     scoped_refptr<CanvasResourceSkiaDawnSharedImage>(this),
                      has_read_ref_on_texture));
 
   scoped_refptr<StaticBitmapImage> image;
@@ -966,7 +966,7 @@
   return image;
 }
 
-const gpu::Mailbox& CanvasResourceWebGPUSharedImage::GetOrCreateGpuMailbox(
+const gpu::Mailbox& CanvasResourceSkiaDawnSharedImage::GetOrCreateGpuMailbox(
     MailboxSyncMode sync_mode) {
   if (!is_cross_thread()) {
     owning_thread_data().mailbox_sync_mode = sync_mode;
@@ -974,11 +974,11 @@
   return mailbox();
 }
 
-bool CanvasResourceWebGPUSharedImage::HasGpuMailbox() const {
+bool CanvasResourceSkiaDawnSharedImage::HasGpuMailbox() const {
   return !mailbox().IsZero();
 }
 
-const gpu::SyncToken CanvasResourceWebGPUSharedImage::GetSyncToken() {
+const gpu::SyncToken CanvasResourceSkiaDawnSharedImage::GetSyncToken() {
   if (is_cross_thread()) {
     // Sync token should be generated at Transfer time, which must always be
     // called before cross-thread usage. And since we don't allow writes on
@@ -1009,7 +1009,7 @@
   return sync_token();
 }
 
-void CanvasResourceWebGPUSharedImage::NotifyResourceLost() {
+void CanvasResourceSkiaDawnSharedImage::NotifyResourceLost() {
   owning_thread_data().is_lost = true;
 
   // Since the texture params are in an unknown state, reset the cached tex
@@ -1020,7 +1020,7 @@
 }
 
 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
-CanvasResourceWebGPUSharedImage::ContextProviderWrapper() const {
+CanvasResourceSkiaDawnSharedImage::ContextProviderWrapper() const {
   DCHECK(!is_cross_thread());
   return context_provider_wrapper_;
 }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.h b/third_party/blink/renderer/platform/graphics/canvas_resource.h
index 947ec193..81bd9cd 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -419,11 +419,11 @@
 };
 
 #if BUILDFLAG(SKIA_USE_DAWN)
-// Resource type for WebGPU SharedImage
-class PLATFORM_EXPORT CanvasResourceWebGPUSharedImage final
+// Resource type for SharedImage that uses Skia and Dawn backend
+class PLATFORM_EXPORT CanvasResourceSkiaDawnSharedImage final
     : public CanvasResourceSharedImage {
  public:
-  static scoped_refptr<CanvasResourceWebGPUSharedImage> Create(
+  static scoped_refptr<CanvasResourceSkiaDawnSharedImage> Create(
       const IntSize&,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
       base::WeakPtr<CanvasResourceProvider>,
@@ -431,7 +431,7 @@
       const CanvasColorParams&,
       bool is_origin_top_left,
       uint32_t shared_image_usage_flags);
-  ~CanvasResourceWebGPUSharedImage() override;
+  ~CanvasResourceSkiaDawnSharedImage() override;
 
   bool IsRecycleable() const final { return true; }
   bool IsAccelerated() const final { return true; }
@@ -483,7 +483,7 @@
   };
 
   static void OnBitmapImageDestroyed(
-      scoped_refptr<CanvasResourceWebGPUSharedImage> resource,
+      scoped_refptr<CanvasResourceSkiaDawnSharedImage> resource,
       bool has_read_ref_on_texture,
       const gpu::SyncToken& sync_token,
       bool is_lost);
@@ -496,7 +496,7 @@
   const gpu::SyncToken GetSyncToken() override;
   bool IsOverlayCandidate() const final { return false; }
 
-  CanvasResourceWebGPUSharedImage(
+  CanvasResourceSkiaDawnSharedImage(
       const IntSize&,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
       base::WeakPtr<CanvasResourceProvider>,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index e16fcda..0004570 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -218,10 +218,10 @@
           context_provider_wrapper,
       bool is_origin_top_left,
       bool is_accelerated,
-      bool use_webgpu,
+      bool skia_use_dawn,
       uint32_t shared_image_usage_flags)
       : CanvasResourceProvider(
-            use_webgpu ? kWebGPUSharedImage : kSharedImage,
+            skia_use_dawn ? kSkiaDawnSharedImage : kSharedImage,
             size,
             filter_quality,
             // TODO(khushalsagar): The software path seems to be assuming N32
@@ -306,8 +306,8 @@
       return nullptr;
 
 #if BUILDFLAG(SKIA_USE_DAWN)
-    if (type_ == kWebGPUSharedImage) {
-      return CanvasResourceWebGPUSharedImage::Create(
+    if (type_ == kSkiaDawnSharedImage) {
+      return CanvasResourceSkiaDawnSharedImage::Create(
           Size(), ContextProviderWrapper(), CreateWeakPtr(), FilterQuality(),
           ColorParams(), IsOriginTopLeft(), shared_image_usage_flags_);
     }
@@ -811,7 +811,7 @@
   kSharedImage,
   kSharedBitmap,
   kBitmap,
-  kWebGPUSharedImage,
+  kSkiaDawnSharedImage,
 };
 
 }  // unnamed namespace
@@ -862,13 +862,13 @@
 
   const auto& capabilities =
       context_provider_wrapper->ContextProvider()->GetCapabilities();
-  bool use_webgpu =
+  bool skia_use_dawn =
       raster_mode == RasterMode::kGPU &&
       base::FeatureList::IsEnabled(blink::features::kDawn2dCanvas);
   // TODO(senorblanco): once Dawn reports maximum texture size, Dawn Canvas
   // should respect it.  http://crbug.com/1082760
-  if (!use_webgpu && (size.Width() > capabilities.max_texture_size ||
-                      size.Height() > capabilities.max_texture_size)) {
+  if (!skia_use_dawn && (size.Width() > capabilities.max_texture_size ||
+                         size.Height() > capabilities.max_texture_size)) {
     return nullptr;
   }
 
@@ -890,7 +890,7 @@
 
   auto provider = std::make_unique<CanvasResourceProviderSharedImage>(
       size, filter_quality, color_params, context_provider_wrapper,
-      is_origin_top_left, raster_mode == RasterMode::kGPU, use_webgpu,
+      is_origin_top_left, raster_mode == RasterMode::kGPU, skia_use_dawn,
       shared_image_usage_flags);
   if (provider->IsValid())
     return provider;
@@ -1241,7 +1241,7 @@
 }
 
 bool CanvasResourceProvider::IsGpuContextLost() const {
-  if (type_ == kWebGPUSharedImage) {
+  if (type_ == kSkiaDawnSharedImage) {
     return false;
   }
   auto* raster_interface = RasterInterface();
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 6cd6cf6d..d10c20d8 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -75,8 +75,8 @@
     kDirectGpuMemoryBuffer = 6,
     kPassThrough = 7,
     kSwapChain = 8,
-    kWebGPUSharedImage = 9,
-    kMaxValue = kWebGPUSharedImage,
+    kSkiaDawnSharedImage = 9,
+    kMaxValue = kSkiaDawnSharedImage,
   };
 
   using RestoreMatrixClipStackCb =
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
index 81a98c7..f35ad4d8 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -411,6 +411,10 @@
         WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
         "For hash maps without traceable elements, use HashMap<> "
         "instead of HeapHashMap<>.");
+    static_assert(internal::IsMemberOrWeakMemberType<KeyArg> ||
+                      !WTF::IsTraceable<KeyArg>::value,
+                  "HeapHashMap supports only Member, WeakMember and "
+                  "non-traceable types as keys.");
   }
 
  public:
diff --git a/third_party/blink/renderer/platform/heap/test/heap_test.cc b/third_party/blink/renderer/platform/heap/test/heap_test.cc
index 1d48f1fb..8fd5c8f3 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_test.cc
@@ -4710,7 +4710,7 @@
   Member<SimpleObject> obj_;
 };
 
-class AllocatesOnAssignment {
+class AllocatesOnAssignment : public GarbageCollected<AllocatesOnAssignment> {
  public:
   AllocatesOnAssignment(std::nullptr_t) : value_(nullptr) {}
   AllocatesOnAssignment(int x) : value_(MakeGarbageCollected<IntWrapper>(x)) {}
@@ -4733,12 +4733,12 @@
 
   inline bool IsDeleted() const { return value_.IsHashTableDeletedValue(); }
 
-  void Trace(Visitor* visitor) const {}
+  void Trace(Visitor* visitor) const { visitor->Trace(value_); }
 
   int Value() { return value_->Value(); }
 
  private:
-  Persistent<IntWrapper> value_;
+  Member<IntWrapper> value_;
 
   friend bool operator==(const AllocatesOnAssignment&,
                          const AllocatesOnAssignment&);
@@ -4756,55 +4756,26 @@
   std::swap(a.value_, b.value_);
 }
 
-struct DegenerateHash {
-  static unsigned GetHash(const AllocatesOnAssignment&) { return 0; }
-  static bool Equal(const AllocatesOnAssignment& a,
-                    const AllocatesOnAssignment& b) {
-    return !a.IsDeleted() && a == b;
-  }
-  static const bool safe_to_compare_to_empty_or_deleted = true;
-};
-
-struct AllocatesOnAssignmentHashTraits
-    : WTF::GenericHashTraits<AllocatesOnAssignment> {
-  typedef AllocatesOnAssignment T;
-  typedef std::nullptr_t EmptyValueType;
-  static EmptyValueType EmptyValue() { return nullptr; }
-  static const bool kEmptyValueIsZero =
-      false;  // Can't be zero if it has a vtable.
-  static void ConstructDeletedValue(T& slot, bool) {
-    slot = T(AllocatesOnAssignment::kDeletedValue);
-  }
-  static bool IsDeletedValue(const T& value) { return value.IsDeleted(); }
-};
-
 }  // namespace blink
 
-namespace WTF {
-
-template <>
-struct DefaultHash<blink::AllocatesOnAssignment> {
-  typedef blink::DegenerateHash Hash;
-};
-
-template <>
-struct HashTraits<blink::AllocatesOnAssignment>
-    : blink::AllocatesOnAssignmentHashTraits {};
-
-}  // namespace WTF
-
 namespace blink {
 
 TEST_F(HeapTest, GCInHashMapOperations) {
-  typedef HeapHashMap<AllocatesOnAssignment, AllocatesOnAssignment> Map;
-  Map* map = MakeGarbageCollected<Map>();
+  typedef HeapHashMap<Member<AllocatesOnAssignment>,
+                      Member<AllocatesOnAssignment>>
+      Map;
+  Persistent<Map> map = MakeGarbageCollected<Map>();
   IntWrapper* key = MakeGarbageCollected<IntWrapper>(42);
-  map->insert(key, AllocatesOnAssignment(103));
-  map->erase(key);
-  for (int i = 0; i < 10; i++)
-    map->insert(AllocatesOnAssignment(i), AllocatesOnAssignment(i));
+  AllocatesOnAssignment* object =
+      MakeGarbageCollected<AllocatesOnAssignment>(key);
+  map->insert(object, MakeGarbageCollected<AllocatesOnAssignment>(103));
+  map->erase(object);
+  for (int i = 0; i < 10; i++) {
+    map->insert(MakeGarbageCollected<AllocatesOnAssignment>(i),
+                MakeGarbageCollected<AllocatesOnAssignment>(i));
+  }
   for (Map::iterator it = map->begin(); it != map->end(); ++it)
-    EXPECT_EQ(it->key.Value(), it->value.Value());
+    EXPECT_EQ(it->key->Value(), it->value->Value());
 }
 
 class PartObjectWithVirtualMethod {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index 899a9d8d..2426ac6 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -68,6 +68,14 @@
   return error;
 }
 
+ResourceError ResourceError::BlockedByResponse(
+    const KURL& url,
+    network::mojom::BlockedByResponseReason blocked_by_response_reason) {
+  ResourceError error(net::ERR_BLOCKED_BY_RESPONSE, url, base::nullopt);
+  error.blocked_by_response_reason_ = blocked_by_response_reason;
+  return error;
+}
+
 ResourceError ResourceError::CacheMissError(const KURL& url) {
   return ResourceError(net::ERR_CACHE_MISS, url, base::nullopt);
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.h b/third_party/blink/renderer/platform/loader/fetch/resource_error.h
index 238efe12..25c33dd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.h
@@ -57,6 +57,9 @@
       const KURL&,
       ResourceRequestBlockedReason,
       const String& localized_description);
+  static ResourceError BlockedByResponse(
+      const KURL&,
+      network::mojom::BlockedByResponseReason);
 
   static ResourceError CacheMissError(const KURL&);
   static ResourceError TimeoutError(const KURL&);
@@ -69,7 +72,7 @@
                 base::Optional<network::CorsErrorStatus>);
   ResourceError(const KURL& failing_url,
                 const network::CorsErrorStatus& status);
-  ResourceError(const WebURLError&);
+  explicit ResourceError(const WebURLError&);
 
   int ErrorCode() const { return error_code_; }
   const String& FailingURL() const { return failing_url_; }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index dad9465ef2..695eebf 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -41,6 +41,7 @@
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/blocked_by_response_reason.mojom-shared.h"
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
 #include "third_party/blink/public/common/client_hints/client_hints.h"
 #include "third_party/blink/public/common/features.h"
@@ -1017,7 +1018,9 @@
       !response.CurrentRequestUrl().ProtocolIsData() &&
       !response.CurrentRequestUrl().ProtocolIs("blob")) {
     DCHECK(!base::FeatureList::IsEnabled(features::kPlzDedicatedWorker));
-    HandleError(ResourceError::Failure(response.CurrentRequestUrl()));
+    HandleError(ResourceError::BlockedByResponse(
+        response.CurrentRequestUrl(), network::mojom::BlockedByResponseReason::
+                                          kCoepFrameResourceNeedsCoepHeader));
     return;
   }
 
@@ -1270,7 +1273,7 @@
   resource_->SetEncodedDataLength(encoded_data_length);
   resource_->SetEncodedBodyLength(encoded_body_length);
   resource_->SetDecodedBodyLength(decoded_body_length);
-  HandleError(error);
+  HandleError(ResourceError(error));
 }
 
 void ResourceLoader::HandleError(const ResourceError& error) {
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1b3ffd5..58ec5aa 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2868,7 +2868,6 @@
 crbug.com/626703 [ Linux ] external/wpt/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html [ Failure ]
-crbug.com/626703 [ Retina ] external/wpt/html/cross-origin-opener-policy/popup-coop-by-sw-from-coop.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/preload/onload-event.html [ Timeout ]
@@ -6848,3 +6847,7 @@
 # Sheriff 2020-08-01
 crbug.com/1112111 fast/forms/month/month-picker-appearance-step.html [ Pass Failure ]
 
+# Sheriff 2020-08-03
+crbug.com/1108423 external/wpt/referrer-policy/gen/worker-classic.http-rp/unset/worker-classic.http.html [ Pass Timeout ]
+crbug.com/1106429 virtual/percent-based-scrolling/max-percent-delta-page-zoom.html [ Pass Failure ]
+crbug.com/1112304 external/wpt/html/cross-origin-opener-policy/popup-coop-by-sw-from-coop.https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_putall.tentative.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_putall.tentative.any.js
index a312d71..8bdc765 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_putall.tentative.any.js
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbobjectstore_putall.tentative.any.js
@@ -3,24 +3,23 @@
 promise_test(async testCase => {
   const db = await createDatabase(testCase, db => {
     const store = createBooksStore(testCase, db);
+    let values = [
+      {isbn: 'one', title: 'title1'},
+      {isbn: 'two', title: 'title2'},
+      {isbn: 'three', title: 'title3'}
+    ];
+    const putAllRequests = store.putAll(values);
+    putAllRequests.forEach(async request => {
+      await promiseForRequest(testCase, request);
+    });
   });
-  const txn = db.transaction(['books'], 'readwrite');
-  const objectStore = txn.objectStore('books');
-  let values = [
-    {isbn: 'one', title: 'title1'},
-    {isbn: 'two', title: 'title2'},
-    {isbn: 'three', title: 'title3'}
-  ];
-  let putAllRequest = objectStore.putAll(values);
-  await promiseForRequest(testCase, putAllRequest);
-  await promiseForTransaction(testCase, txn);
 
-  const txn2 = db.transaction(['books'], 'readonly');
-  const objectStore2 = txn2.objectStore('books');
-  const getRequest1 = objectStore2.get('one');
-  const getRequest2 = objectStore2.get('two');
-  const getRequest3 = objectStore2.get('three');
-  await promiseForTransaction(testCase, txn2);
+  const txn = db.transaction(['books'], 'readonly');
+  const objectStore = txn.objectStore('books');
+  const getRequest1 = objectStore.get('one');
+  const getRequest2 = objectStore.get('two');
+  const getRequest3 = objectStore.get('three');
+  await promiseForTransaction(testCase, txn);
   assert_array_equals(
       [getRequest1.result.title,
           getRequest2.result.title,
@@ -28,4 +27,4 @@
       ['title1', 'title2', 'title3'],
       'All three retrieved titles should match those that were put.');
   db.close();
-}, 'Data can be successfully inputted into an object store using putAll.');
+}, 'Data can be successfully inputted into an object store using putAll.');
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer-expected.txt
new file mode 100644
index 0000000..9dadb68
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Opener COOP assert_equals: No report received. expected 1 but got 0
+FAIL Openee COOP assert_equals: No report received. expected 1 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
new file mode 100644
index 0000000..4d1eda94
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
@@ -0,0 +1,135 @@
+<title>
+  Check the ReportingObserver(s) are notified about the coop-access-violation
+  events.
+</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/dispatcher.js"></script>
+<script src="../resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy/reporting";
+const executor_path = directory + "/resources/executor.html?pipe=";
+const https = get_host_info().HTTPS_ORIGIN;
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+promise_test(async t => {
+  // This test window.
+  const this_window_token = token();
+
+  // The "opener" window, using COOP-Report-Only and a reporter.
+  const opener_token = token();
+  const opener_reportTo = reportToHeaders(token());
+  const opener_url = https + executor_path + opener_reportTo.header +
+    opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+    `&uuid=${opener_token}`;
+
+  // The "openee" window, NOT using COOP.
+  const openee_token = token();
+  const openee_url = https + executor_path + `&uuid=${openee_token}`;
+
+  // 1. Create the opener window.
+  window.open(opener_url);
+  t.add_cleanup(() => send(opener_token, "window.close();"));
+
+  // 2. The opener opens its openee.
+  send(opener_token, `openee = window.open('${openee_url}');`);
+  t.add_cleanup(() => send(openee_token, `window.close();`));
+
+  // 3. Wait for the openee to load its document.
+  send(openee_token, `send("${this_window_token}", "Ready");`);
+  assert_equals(await receive(this_window_token), "Ready");
+
+  // 4. The opener tries to access its openee. All reports for blocked access
+  //    from the COOP page should notify the ReportingObservers.
+  send(opener_token, `
+    let observer = new ReportingObserver(()=>{});
+    observer.observe();
+    tryAccess(openee);
+    let reports = observer.takeRecords();
+    send("${this_window_token}", JSON.stringify(reports));
+    observer.disconnect();
+  `);
+
+  let report_access_from = JSON.parse(await receive(this_window_token));
+  assert_equals(report_access_from.length, 1, "No report received.");
+  assert_equals(report_access_from[0].type, "coop-access-violation");
+  assert_equals(report_access_from[0].url, opener_url.replace(/"/g, '%22'));
+  assert_true(report_access_from[0].body.sourceFile.includes("try-access.js"));
+  assert_equals(report_access_from[0].body.lineNumber, 6);
+  assert_equals(report_access_from[0].body.columnNumber, 7);
+  assert_equals(report_access_from[0].body.property, "blur");
+
+  // 5. The openee tries to access its opener. No reports for blocked access
+  //    to the COOP page should be dispatched.
+  send(openee_token, `
+    let observer = new ReportingObserver(()=>{});
+    observer.observe();
+    tryAccess(opener);
+    let reports = observer.takeRecords();
+    send("${this_window_token}", JSON.stringify(reports));
+    observer.disconnect();
+  `);
+  let report_access_to = JSON.parse(await receive(this_window_token));
+  assert_equals(report_access_to.length, 0, "Unexpected report received.");
+}, "Opener COOP");
+
+promise_test(async t => {
+  // This test window.
+  const this_window_token = token();
+
+  // The "opener" window, NOT using COOP.
+  const opener_token = token();
+  const opener_url = https + executor_path + `&uuid=${opener_token}`;
+
+  // The "openee" window, using COOP-Report-Only and a reporter.
+  const openee_token = token();
+  const openee_reportTo = reportToHeaders(token());
+  const openee_url = https + executor_path + openee_reportTo.header +
+    openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
+    `&uuid=${openee_token}`;
+
+  // 1. Create the opener window.
+  window.open(opener_url);
+  t.add_cleanup(() => send(opener_token, "window.close();"));
+
+  // 2. The opener opens its openee.
+  send(opener_token,
+    `openee = window.open('${openee_url.replace(/,/g, '\\,')}');`);
+  t.add_cleanup(() => send(openee_token, `window.close();`));
+
+  // 3. The openee tries to access its opener. All reports for blocked access
+  //    from the COOP page should notify the ReportingObservers.
+  send(openee_token, `
+    let observer = new ReportingObserver(()=>{});
+    observer.observe();
+    tryAccess(opener);
+    let reports = observer.takeRecords();
+    send("${this_window_token}", JSON.stringify(reports));
+    observer.disconnect();
+  `);
+  let report_access_from = JSON.parse(await receive(this_window_token));
+  assert_equals(report_access_from.length, 1, "No report received.");
+  assert_equals(report_access_from[0].type, "coop-access-violation");
+  assert_equals(report_access_from[0].url, openee_url.replace(/"/g, '%22'));
+  assert_true(report_access_from[0].body.sourceFile.includes("try-access.js"));
+  assert_equals(report_access_from[0].body.lineNumber, 6);
+  assert_equals(report_access_from[0].body.columnNumber, 7);
+  assert_equals(report_access_from[0].body.property, "blur");
+
+  // 4. The opener tries to access its openee. No reports for blocked access
+  //    to the COOP page should be dispatched.
+  send(opener_token, `
+    let observer = new ReportingObserver(()=>{});
+    observer.observe();
+    tryAccess(openee);
+    let reports = observer.takeRecords();
+    send("${this_window_token}", JSON.stringify(reports));
+    observer.disconnect();
+  `);
+  let report_access_to = JSON.parse(await receive(this_window_token));
+  assert_equals(report_access_to.length, 0, "Unexpected report received.");
+}, "Openee COOP");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https-expected.txt
new file mode 100644
index 0000000..2097b2e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cross-origin openee redirected to same-origin with same-origin-allow-popups assert_equals: opener expected "false" but got "true"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
new file mode 100644
index 0000000..7dba76c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
@@ -0,0 +1,84 @@
+<title>
+  COOP reports are to the opener when the opener used COOP-RO+COEP and then its
+  cross-origin openee tries to access it.
+</title>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/dispatcher.js"></script>
+<script src="../resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy/reporting";
+const executor_path = directory + "/resources/executor.html?pipe=";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+promise_test(async t => {
+  // The test window.
+  const this_window_token = token();
+
+  // The "opener" window. This has COOP same-origin-allow-popups and a reporter.
+  const opener_report_token= token();
+  const opener_token = token();
+  const opener_reportTo = reportToHeaders(opener_report_token);
+  const opener_url = same_origin + executor_path + opener_reportTo.header +
+    opener_reportTo.coopSameOriginAllowPopupsHeader +
+    `&uuid=${opener_token}`;
+
+  // The "openee" window.
+  // The initial URL is cross-origin with the opener, and redirects to a
+  // same-origin page with same-origin-allow-popups.
+  // The navigation to the cross-origin page stays in the same browsing context
+  // group due to the same-origin-allow-popups policy, but the redirect to the
+  // final page does since it compares the cross-origin/unsafe-none document
+  // with the same-origin/same-origin-allow-popups document.
+  const openee_token = token();
+  const openee_redirect_url = same_origin + executor_path +
+    opener_reportTo.header + opener_reportTo.coopSameOriginAllowPopupsHeader +
+    `&uuid=${openee_token}`;
+  const redirect_header = 'status(302)' +
+    `|header(Location,${encodeURIComponent(
+      openee_redirect_url
+        .replace(/,/g, "\\,")
+        .replace(/\\\\,/g, "\\\\\\,")
+        .replace(/\(/g, "%28")
+        .replace(/\)/g, "%29"))})`;
+  const openee_url = cross_origin + executor_path + redirect_header +
+    `&uuid=${openee_token}`;
+  // 1. Create the opener window.
+  let opener_window_proxy = window.open(opener_url);
+  t.add_cleanup(() => send(opener_token, "window.close()"));
+
+  // 2. The opener opens its openee.
+  send(opener_token, `
+    openee = window.open("${openee_url}");
+  `);
+  t.add_cleanup(() => send(openee_token, "window.close()"));
+
+  // 3. Check the opener status on the openee.
+  send(openee_token, `
+    send("${this_window_token}", opener !== null);
+  `);
+  assert_equals(await receive(this_window_token), "false", "opener");
+
+  // 4. Check the openee status on the opener.
+  send(opener_token, `
+    send("${this_window_token}", openee.closed);
+  `);
+  assert_equals(await receive(this_window_token), "true", "openee.closed");
+
+  // 5. Check a report sent to the openee.
+  let report = await receiveReport(opener_report_token, "navigation-to-document")
+  assert_not_equals(report, "timeout", "Report not received");
+  assert_equals(report.type, "coop");
+  assert_equals(report.url, openee_redirect_url.replace(/"/g, '%22'));
+  assert_equals(report.body["disposition"], "enforce");
+  assert_equals(report.body["effective-policy"], "same-origin-allow-popups");
+  assert_equals(report.body["document-uri"], openee_url);
+}, "Cross-origin openee redirected to same-origin with same-origin-allow-popups");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/resources/dispatcher.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/resources/dispatcher.js
index 38243fa..13c01ad 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/resources/dispatcher.js
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/resources/dispatcher.js
@@ -64,6 +64,8 @@
   return {
     header: `|header(report-to,${reportToJSON})`,
     coopSameOriginHeader: `|header(Cross-Origin-Opener-Policy,same-origin%3Breport-to="${uuid}")`,
+    coopSameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy,same-origin-allow-popups%3Breport-to="${uuid}")`,
     coopReportOnlySameOriginHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin%3Breport-to="${uuid}")`,
+    coopReportOnlySameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin-allow-popups%3Breport-to="${uuid}")`,
   };
 };
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/coep-load-error-reporting-worker-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/coep-load-error-reporting-worker-expected.txt
new file mode 100644
index 0000000..f303a6a
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/coep-load-error-reporting-worker-expected.txt
@@ -0,0 +1,6 @@
+Tests that cross-origin embedder policy (COEP) related blocking for worker sources is reported correctly.
+https://devtools.test:8443/inspector-protocol/network/cross-origin-isolation/resources/coep-page-with-worker.php: *loading finished*
+https://devtools.test:8443/inspector-protocol/network/cross-origin-isolation/resources/script-with-coep-corp.php: net::ERR_BLOCKED_BY_RESPONSE coep-frame-resource-needs-coep-header
+https://devtools.test:8443/inspector-protocol/network/cross-origin-isolation/resources/script-with-coep-corp.php?coep: *loading finished*
+https://devtools.test:8443/inspector-protocol/network/cross-origin-isolation/resources/script-with-coep-corp.php?coep&corp=same-site: *loading finished*
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/coep-load-error-reporting-worker.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/coep-load-error-reporting-worker.js
new file mode 100644
index 0000000..dfac94f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/coep-load-error-reporting-worker.js
@@ -0,0 +1,60 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      `Tests that cross-origin embedder policy (COEP) related blocking for worker sources is reported correctly.`);
+
+  await session.protocol.Network.clearBrowserCache();
+  await session.protocol.Network.setCacheDisabled({cacheDisabled: true});
+  await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
+
+  setTimeout(() => dump(), 5000);
+
+  let numberOfMessages = 0;
+  const expectedNumberOfMessages = 21;
+  const resources = new Map();
+
+  function dump() {
+    function compareInfo(a, b) {
+      return `${a.requestWillBeSent?.request?.url}`.localeCompare(`${b.requestWillBeSent?.request?.url}`);
+    }
+    const entries = Array.from(resources.values()).sort(compareInfo);
+    for (const entry of entries) {
+      if (entry.loadingFailed) {
+        testRunner.log(`${entry.requestWillBeSent.request?.url}: ${entry.loadingFailed.errorText} ${entry.loadingFailed.blockedReason}`);
+      }
+      if (entry.loadingFinished) {
+        testRunner.log(`${entry.requestWillBeSent.request?.url}: *loading finished*`);
+      }
+    }
+    testRunner.completeTest();
+  }
+
+  function record(requestId, info) {
+    resources.set(requestId, {...resources.get(requestId), ...info});
+
+    if (++numberOfMessages === expectedNumberOfMessages) {
+      dump();
+    }
+  }
+
+  async function initalizeTarget(dp) {
+    dp.Network.onLoadingFailed(event => record(event.params.requestId, {loadingFailed: event.params})),
+    dp.Network.onLoadingFinished(event => record(event.params.requestId, {loadingFinished: event.params})),
+    dp.Network.onRequestWillBeSent(event => record(event.params.requestId, {requestWillBeSent: event.params})),
+    await Promise.all([
+      dp.Network.enable(),
+      dp.Page.enable()
+    ]);
+  }
+
+  await initalizeTarget(dp);
+
+  dp.Target.onAttachedToTarget(async e => {
+    const dp = session.createChild(e.params.sessionId).protocol;
+    await initalizeTarget(dp);
+  });
+
+  page.navigate('https://devtools.test:8443/inspector-protocol/network/cross-origin-isolation/resources/coep-page-with-worker.php');
+
+  // `record` above makes sure to complete the test.
+})
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/resources/coep-page-with-worker.php b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/resources/coep-page-with-worker.php
new file mode 100644
index 0000000..a072d40
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/resources/coep-page-with-worker.php
@@ -0,0 +1,21 @@
+<?php
+
+header("Cross-Origin-Embedder-Policy: require-corp");
+
+?>
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <title>Page with Cross-Origin-Embedder-Policy</title>
+    <meta charset="utf-8">
+  </head>
+  <body>
+    <script>
+      const worker = new Worker("script-with-coep-corp.php");
+      const worker2 = new Worker("script-with-coep-corp.php?coep");
+      const worker3 = new Worker("script-with-coep-corp.php?coep&corp=same-site");
+    </script>
+  </body>
+</html>
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/resources/script-with-coep-corp.php b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/resources/script-with-coep-corp.php
new file mode 100644
index 0000000..62e0d6e
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/cross-origin-isolation/resources/script-with-coep-corp.php
@@ -0,0 +1,18 @@
+<?php
+
+if (isset($_GET['corp'])) {
+  header("Cross-Origin-Resource-Policy: " . $_GET['corp']);
+}
+
+if (isset($_GET['coop'])) {
+  header("Cross-Origin-Opener-Policy: same-origin");
+}
+
+
+if (isset($_GET['coep'])) {
+  header("Cross-Origin-Embedder-Policy: require-corp");
+}
+
+console.log("Hello from script");
+
+?>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 08568fa..859ad44c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -37154,6 +37154,9 @@
 <enum name="IOSMenuAction">
   <int value="0" label="Copy"/>
   <int value="1" label="Delete"/>
+  <int value="2" label="Open in New Tab"/>
+  <int value="3" label="Open in New Incognito Tab"/>
+  <int value="4" label="Open in New Window"/>
 </enum>
 
 <enum name="IOSMenuScenario">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index bf6803b..b3b0fa7 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -4636,7 +4636,7 @@
 </histogram>
 
 <histogram name="Android.SelectFileDialogImgCount" units="images"
-    expires_after="2021-07-17">
+    expires_after="M90">
   <owner>finnur@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -4648,7 +4648,7 @@
 </histogram>
 
 <histogram name="Android.SelectFileDialogScope" enum="SelectFileDialogScope"
-    expires_after="2021-07-17">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>finnur@chromium.org</owner>
   <summary>
@@ -63333,7 +63333,7 @@
 </histogram>
 
 <histogram name="GCM.AccountMappingMessageReceived" enum="BooleanReceived"
-    expires_after="2020-08-25">
+    expires_after="M88">
   <owner>peter@chromium.org</owner>
   <owner>knollr@chromium.org</owner>
   <summary>
@@ -63380,7 +63380,7 @@
 </histogram>
 
 <histogram name="GCM.CheckinRequestStatusNetError" enum="NetErrorCodes"
-    expires_after="2020-08-30">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>knollr@chromium.org</owner>
   <summary>
@@ -63509,7 +63509,7 @@
 </histogram>
 
 <histogram name="GCM.Crypto.InitKeyStoreSuccessRate" enum="BooleanSuccess"
-    expires_after="2020-08-25">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>zea@chromium.org</owner>
   <summary>
@@ -71569,7 +71569,7 @@
 </histogram>
 
 <histogram name="InstanceID.GetToken.NetErrorCode" enum="NetErrorCodes"
-    expires_after="2020-08-25">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>platform-capabilities@chromium.org</owner>
   <summary>
@@ -111828,7 +111828,7 @@
 </histogram>
 
 <histogram name="Notifications.Database.DeleteAllForOriginsResult"
-    enum="NotificationDatabaseStatus" expires_after="M86">
+    enum="NotificationDatabaseStatus" expires_after="M90">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -111910,7 +111910,7 @@
 </histogram>
 
 <histogram name="Notifications.Database.ReadResourcesForTriggeredResult"
-    enum="NotificationDatabaseStatus" expires_after="M86">
+    enum="NotificationDatabaseStatus" expires_after="M90">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -111921,7 +111921,7 @@
 </histogram>
 
 <histogram name="Notifications.Database.ReadResourcesResult"
-    enum="NotificationDatabaseStatus" expires_after="M86">
+    enum="NotificationDatabaseStatus" expires_after="M90">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -111952,7 +111952,7 @@
 </histogram>
 
 <histogram name="Notifications.Database.WriteTriggeredResult"
-    enum="NotificationDatabaseStatus" expires_after="M86">
+    enum="NotificationDatabaseStatus" expires_after="M90">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -111991,6 +111991,10 @@
 
 <histogram name="Notifications.ExtensionNotificationActionCount"
     units="buttons" expires_after="M86">
+  <obsolete>
+    Removed in July 2020 as the metrics are not needed anymore, and
+    documentation has been amended as a result of this collection.
+  </obsolete>
   <owner>dewittj@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -112018,6 +112022,10 @@
 
 <histogram name="Notifications.ExtensionNotificationType"
     enum="ExtensionNotificationType" expires_after="M86">
+  <obsolete>
+    Removed in July 2020 as the metrics are not needed anymore as platforms have
+    moved to native notifications, for which these metrics were used.
+  </obsolete>
   <owner>dewittj@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -112226,7 +112234,7 @@
 </histogram>
 
 <histogram name="Notifications.Permissions.RevokeDeleteCount" units="units"
-    expires_after="M86">
+    expires_after="M90">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -112503,6 +112511,9 @@
 
 <histogram name="Notifications.Triggers.HasShowTrigger" enum="Boolean"
     expires_after="M86">
+  <obsolete>
+    Removed July 2020 as the Origin Trial is ramping down.
+  </obsolete>
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -112514,6 +112525,9 @@
 
 <histogram name="Notifications.Triggers.ShowTriggerDelay" units="days"
     expires_after="M86">
+  <obsolete>
+    Removed July 2020 as the Origin Trial is ramping down.
+  </obsolete>
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -141216,7 +141230,7 @@
 </histogram>
 
 <histogram name="PushMessaging.UnregistrationIIDResult" enum="InstanceIDResult"
-    expires_after="2020-08-25">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>knollr@chromium.org</owner>
   <summary>
@@ -158660,7 +158674,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.NotificationClickEvent.Time" units="ms"
-    expires_after="2020-08-25">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>knollr@chromium.org</owner>
   <summary>
@@ -177870,7 +177884,7 @@
 </histogram>
 
 <histogram name="TabManager.Discarding.DiscardCount" units="Discards"
-    expires_after="M85">
+    expires_after="M100">
   <owner>sebmarchand@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -177923,7 +177937,7 @@
 </histogram>
 
 <histogram name="TabManager.Discarding.DiscardToReloadTime" units="ms"
-    expires_after="M85">
+    expires_after="M100">
   <owner>sebmarchand@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -177933,7 +177947,7 @@
 </histogram>
 
 <histogram name="TabManager.Discarding.InactiveToReloadTime" units="ms"
-    expires_after="M85">
+    expires_after="M100">
   <owner>sebmarchand@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -178005,7 +178019,7 @@
 </histogram>
 
 <histogram name="TabManager.Discarding.ReloadCount" units="Reloads"
-    expires_after="M85">
+    expires_after="M100">
   <owner>sebmarchand@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -178032,7 +178046,7 @@
 </histogram>
 
 <histogram name="TabManager.Discarding.ReloadToCloseTime" units="ms"
-    expires_after="M85">
+    expires_after="M100">
   <owner>sebmarchand@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -189981,7 +189995,7 @@
 </histogram>
 
 <histogram name="Webapp.NavigationStatus" enum="BooleanSuccess"
-    expires_after="2020-08-25">
+    expires_after="M90">
   <owner>peter@chromium.org</owner>
   <owner>hartmanng@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 4d550faf..e4b994d7 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -4967,6 +4967,7 @@
 <event name="HistoryNavigation" singular="True">
   <owner>altimin@chromium.org</owner>
   <owner>arthursonzogni@chromium.org</owner>
+  <owner>hajimehoshi@chromium.org</owner>
   <summary>
     Metrics recorded each time we commit a history navigation, which are needed
     to estimate benefits of back-forward cache. Except as otherwise noted, the
@@ -4992,6 +4993,22 @@
       individual features.
     </summary>
   </metric>
+  <metric name="CumulativeShiftScoreAfterBackForwardCacheRestore">
+    <summary>
+      Measures the cumulative layout shift (bit.ly/3fQz29y) that has occurred
+      during the session, after the page is restored from the back-forward
+      cache. This metric's integral value is 100x the fractional cumulative
+      layout shift score described in the explainer.
+    </summary>
+  </metric>
+  <metric name="FirstInputDelayAfterBackForwardCacheRestore">
+    <summary>
+      Measures First Input Delay, the duration between the hardware timestamp
+      and the start of event processing on the main thread for the first
+      meaningful input per navigation, after the page is restored from the
+      back-forward cache.
+    </summary>
+  </metric>
   <metric name="LastCommittedCrossDocumentNavigationSourceIdForTheSameDocument">
     <summary>
       For history navigations and reloads, the source id of the previous
@@ -5024,6 +5041,13 @@
       It's expected to be rare, but might be problematic for back-forward cache.
     </summary>
   </metric>
+  <metric name="NavigationToFirstPaintAfterBackForwardCacheRestore">
+    <summary>
+      Measures the time in milliseconds from navigation timing's navigation
+      start to the time the first paint is performed, after the page is restored
+      from the back-forward cache.
+    </summary>
+  </metric>
   <metric name="SameOriginSubframesFeatures">
     <summary>
       Bitmask of features used by the same origin subframes of the previous page
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index db35cf5..30875a3 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,12 +5,12 @@
             "remote_path": "perfetto_binaries/trace_processor_shell/win/fce06b20005cdc2e98d266719088811c65eecf0f/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "41e5a50575a0679ce4468f753ee9a2e06568ae7a",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/fce06b20005cdc2e98d266719088811c65eecf0f/trace_processor_shell"
+            "hash": "d91a66af4c71d73ae41ad3be3ba83eeeb5ea228a",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/0f08cdebc12b8d432cff424393901a53e98feef1/trace_processor_shell"
         },
         "linux": {
-            "hash": "f2d163e0cfc524ae3d8d0f4434283a93b87fbb38",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/fce06b20005cdc2e98d266719088811c65eecf0f/trace_processor_shell"
+            "hash": "f19c2e845634058155c317f40f583a3145f9338a",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/4b656a010be50665d73995d66c5f5a544262b10f/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 67f5270f..d3c4282 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -381,10 +381,12 @@
 crbug.com/1023366 [ desktop ] v8.browsing_desktop/browse:media:youtube:2019 [ Skip ]
 crbug.com/1101855 [ mac ] v8.browsing_desktop/browse:tools:gmail-compose:2020 [ Skip ]
 crbug.com/1101855 [ win ] v8.browsing_desktop/browse:tools:gmail-compose:2020 [ Skip ]
+crbug.com/1111593 [ linux ] v8.browsing_desktop/browse:tools:gmail-compose:2020 [ Skip ]
 crbug.com/1100138 [ desktop ] v8.browsing_desktop/browse:tools:gmail-labelclick:2020 [ skip ]
 crbug.com/1100138 [ desktop ] v8.browsing_desktop/browse:tools:gmail-openconversation:2020 [ skip ]
 crbug.com/1100138 [ desktop ] v8.browsing_desktop/browse:tools:gmail-search:2020 [ skip ]
 crbug.com/1104211 [ win ] v8.browsing_desktop/browse:news:cnn:2020 [ skip ]
+crbug.com/1105592 [ desktop ] v8.browsing_desktop/browse:news:nytimes:2020 [ skip ]
 
 # Benchmark v8.browsing_desktop-future
 crbug.com/788796 [ linux ] v8.browsing_desktop-future/browse:media:imgur [ Skip ]
@@ -396,10 +398,12 @@
 crbug.com/1057975 [ mac ] v8.browsing_desktop-future/browse:tools:maps:2019 [ Skip ]
 crbug.com/1101855 [ mac ] v8.browsing_desktop-future/browse:tools:gmail-compose:2020 [ Skip ]
 crbug.com/1101855 [ win ] v8.browsing_desktop-future/browse:tools:gmail-compose:2020 [ Skip ]
+crbug.com/1111593 [ linux ] v8.browsing_desktop-future/browse:tools:gmail-compose:2020 [ Skip ]
 crbug.com/1100138 [ desktop ] v8.browsing_desktop-future/browse:tools:gmail-labelclick:2020 [ skip ]
 crbug.com/1100138 [ desktop ] v8.browsing_desktop-future/browse:tools:gmail-openconversation:2020 [ skip ]
 crbug.com/1100138 [ desktop ] v8.browsing_desktop-future/browse:tools:gmail-search:2020 [ skip ]
 crbug.com/1104211 [ win ] v8.browsing_desktop-future/browse:news:cnn:2020 [ skip ]
+crbug.com/1105592 [ desktop ] v8.browsing_desktop-future/browse:news:nytimes:2020 [ skip ]
 
 # Benchmark: v8.browsing_mobile
 crbug.com/958034 [ android-go android-webview ] v8.browsing_mobile/* [ Skip ]
diff --git a/ui/accessibility/platform/ax_platform_node.cc b/ui/accessibility/platform/ax_platform_node.cc
index 4f8d630..6bf1a7a 100644
--- a/ui/accessibility/platform/ax_platform_node.cc
+++ b/ui/accessibility/platform/ax_platform_node.cc
@@ -62,14 +62,6 @@
   return GetDelegate() ? GetDelegate()->GetUniqueId().Get() : -1;
 }
 
-void AXPlatformNode::SetIsPrimaryWebContentsForWindow(bool is_primary) {
-  is_primary_web_contents_for_window_ = is_primary;
-}
-
-bool AXPlatformNode::IsPrimaryWebContentsForWindow() const {
-  return is_primary_web_contents_for_window_;
-}
-
 std::string AXPlatformNode::ToString() {
   return GetDelegate() ? GetDelegate()->ToString() : "No delegate";
 }
diff --git a/ui/accessibility/platform/ax_platform_node.h b/ui/accessibility/platform/ax_platform_node.h
index e8ad7ed..24b33ca8 100644
--- a/ui/accessibility/platform/ax_platform_node.h
+++ b/ui/accessibility/platform/ax_platform_node.h
@@ -92,10 +92,6 @@
   // Return true if this object is equal to or a descendant of |ancestor|.
   virtual bool IsDescendantOf(AXPlatformNode* ancestor) const = 0;
 
-  // Set |this| as the primary web contents for the window.
-  void SetIsPrimaryWebContentsForWindow(bool is_primary);
-  bool IsPrimaryWebContentsForWindow() const;
-
   // Return the unique ID.
   int32_t GetUniqueId() const;
 
@@ -129,8 +125,6 @@
   // underlying content.
   static gfx::NativeViewAccessible popup_focus_override_;
 
-  bool is_primary_web_contents_for_window_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(AXPlatformNode);
 };
 
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index af7f130..2fe51ea5 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -2497,10 +2497,7 @@
   frame->SetDocumentParent(parent_atk_object);
 }
 
-AtkObject* AXPlatformNodeAuraLinux::FindPrimaryWebContentDocument() {
-  // It could get multiple web contents since additional web content is added,
-  // when the DevTools window is opened.
-  std::vector<AtkObject*> web_content_candidates;
+AtkObject* AXPlatformNodeAuraLinux::FindFirstWebContentDocument() {
   for (auto child_iterator_ptr = GetDelegate()->ChildrenBegin();
        *child_iterator_ptr != *GetDelegate()->ChildrenEnd();
        ++(*child_iterator_ptr)) {
@@ -2512,36 +2509,12 @@
       continue;
     if (child_node->GetAtkRole() != ATK_ROLE_DOCUMENT_WEB)
       continue;
-    web_content_candidates.push_back(child);
+    return child;
   }
 
-  if (web_content_candidates.empty())
-    return nullptr;
-
-  // If it finds just one web content, return it.
-  if (web_content_candidates.size() == 1)
-    return web_content_candidates[0];
-
-  for (auto* object : web_content_candidates) {
-    auto* child_node = AXPlatformNodeAuraLinux::FromAtkObject(object);
-    // If it is a primary web contents, return it.
-    if (child_node->IsPrimaryWebContentsForWindow())
-      return object;
-  }
   return nullptr;
 }
 
-bool AXPlatformNodeAuraLinux::IsWebDocumentForRelations() {
-  AtkObject* atk_object = GetOrCreateAtkObject();
-  if (!atk_object)
-    return false;
-  AXPlatformNodeAuraLinux* parent = FromAtkObject(GetParent());
-  if (!parent || !GetDelegate()->IsWebContent() ||
-      GetAtkRole() != ATK_ROLE_DOCUMENT_WEB)
-    return false;
-  return parent->FindPrimaryWebContentDocument() == atk_object;
-}
-
 AtkObject* AXPlatformNodeAuraLinux::CreateAtkObject() {
   if (GetData().role != ax::mojom::Role::kApplication &&
       !GetDelegate()->IsToplevelBrowserWindow() &&
@@ -3210,7 +3183,7 @@
 
   AtkRelationSet* relation_set = atk_relation_set_new();
 
-  if (IsWebDocumentForRelations()) {
+  if (GetDelegate()->IsWebContent() && GetAtkRole() == ATK_ROLE_DOCUMENT_WEB) {
     AtkObject* parent_frame = FindAtkObjectParentFrame(atk_object);
     if (parent_frame) {
       atk_relation_set_add_relation_by_type(
@@ -3219,7 +3192,7 @@
   }
 
   if (auto* document_parent = FromAtkObject(document_parent_)) {
-    AtkObject* document = document_parent->FindPrimaryWebContentDocument();
+    AtkObject* document = document_parent->FindFirstWebContentDocument();
     if (document) {
       atk_relation_set_add_relation_by_type(relation_set, ATK_RELATION_EMBEDS,
                                             document);
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
index 6c63a19..f4cfa87 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -340,11 +340,8 @@
   // the toplevel frame which contains the node.
   void SetDocumentParentOnFrameIfNecessary();
 
-  // Find the child which is a document containing the primary web content.
-  AtkObject* FindPrimaryWebContentDocument();
-
-  // Returns true if it is a web content for the relations.
-  bool IsWebDocumentForRelations();
+  // Find the first child which is a document containing web content.
+  AtkObject* FindFirstWebContentDocument();
 
   // If a selection that intersects this node get the full selection
   // including start and end node ids.
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index 187c455..4df6e85 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -138,6 +138,8 @@
     sources = [
       "fake_message_center.cc",
       "fake_message_center.h",
+      "lock_screen/fake_lock_screen_controller.cc",
+      "lock_screen/fake_lock_screen_controller.h",
     ]
 
     deps = [
@@ -160,8 +162,6 @@
     }
 
     sources = [
-      "lock_screen/fake_lock_screen_controller.cc",
-      "lock_screen/fake_lock_screen_controller.h",
       "message_center_impl_unittest.cc",
       "notification_list_unittest.cc",
       "public/cpp/notification_delegate_unittest.cc",
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc
index 639ba0b..b3c8633f 100644
--- a/ui/views/controls/webview/webview.cc
+++ b/ui/views/controls/webview/webview.cc
@@ -272,17 +272,8 @@
   if (web_contents() && !web_contents()->IsCrashed()) {
     content::RenderWidgetHostView* host_view =
         web_contents()->GetRenderWidgetHostView();
-    if (host_view) {
-      gfx::NativeViewAccessible accessible =
-          host_view->GetNativeViewAccessible();
-      // |accessible| needs to know whether this is the primary WebContents.
-      if (auto* ax_platform_node =
-              ui::AXPlatformNode::FromNativeViewAccessible(accessible)) {
-        ax_platform_node->SetIsPrimaryWebContentsForWindow(
-            is_primary_web_contents_for_window_);
-      }
-      return accessible;
-    }
+    if (host_view)
+      return host_view->GetNativeViewAccessible();
   }
   return View::GetNativeViewAccessible();
 }
diff --git a/ui/views/controls/webview/webview.h b/ui/views/controls/webview/webview.h
index f18eea14..cfcf301 100644
--- a/ui/views/controls/webview/webview.h
+++ b/ui/views/controls/webview/webview.h
@@ -89,11 +89,6 @@
   // if the web contents is changed.
   void SetCrashedOverlayView(View* crashed_overlay_view);
 
-  // Sets whether this is the primary web contents for the window.
-  void set_is_primary_web_contents_for_window(bool is_primary) {
-    is_primary_web_contents_for_window_ = is_primary;
-  }
-
   // When used to host UI, we need to explicitly allow accelerators to be
   // processed. Default is false.
   void set_allow_accelerators(bool allow_accelerators) {
@@ -204,7 +199,6 @@
   content::BrowserContext* browser_context_;
   bool allow_accelerators_ = false;
   View* crashed_overlay_view_ = nullptr;
-  bool is_primary_web_contents_for_window_ = false;
 
   // Minimum and maximum sizes to determine WebView bounds for auto-resizing.
   // Empty if auto resize is not enabled.